Почему размер таблицы InnoDB намного больше ожидаемого? - PullRequest
8 голосов
/ 26 мая 2010

Я пытаюсь выяснить требования к хранилищу для разных механизмов хранения. У меня есть эта таблица:

CREATE TABLE  `mytest` (
  `num1` int(10) unsigned NOT NULL,
  KEY `key1` (`num1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Когда я вставляю некоторые значения и затем запускаю show table status;, я получаю следующее:

+----------------+--------+---------+------------+---------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+
| Name           | Engine | Version | Row_format | Rows    | Avg_row_length | Data_length | Max_data_length  | Index_length | Data_free | Auto_increment | Create_time         | Update_time         | Check_time | Collation         | Checksum | Create_options | Comment |
+----------------+--------+---------+------------+---------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+
| mytest         | InnoDB |      10 | Compact    | 1932473 |             35 |    67715072 |                0 |     48840704 |   4194304 |           NULL | 2010-05-26 11:30:40 | NULL                | NULL       | latin1_swedish_ci |     NULL |                |         |

Обратите внимание, что avg_row_length 35. Я озадачен тем, что InnoDB не будет лучше использовать пространство, когда я просто храню ненулевое целое число.

Я выполнил этот же тест на myISAM, и по умолчанию myISAM использует 7 байтов на строку в этой таблице. Когда я бегу

ALTER TABLE mytest MAX_ROWS=50000000, AVG_ROW_LENGTH = 4;

заставляет myISAM наконец корректно использовать 5-байтовые строки.

Когда я запускаю ту же инструкцию ALTER TABLE для InnoDB, длина avg_row_length не изменяется.

Зачем такая большая длина avg_row_length необходима при сохранении только 4-байтового целого без знака?

Ответы [ 3 ]

10 голосов
/ 26 мая 2010

InnoDB таблицы сгруппированы, это означает, что все данные содержатся в B-Tree с PRIMARY KEY в качестве ключа и всеми другими столбцами в качестве полезной нагрузки.

Поскольку вы не определяете явное PRIMARY KEY, InnoDB использует скрытый 6-байтовый столбец для сортировки записей.

Это и служебные данные B-Tree организации (с дополнительными блоками не-листового уровня) требуют больше места, чем sizeof(int) * num_rows.

2 голосов
/ 11 апреля 2012

Вот еще некоторая информация, которая может оказаться полезной.

InnoDB распределяет данные в терминах страниц по 16 КБ, поэтому «SHOW TABLE STATUS» выдаст завышенные числа для размера строки, если у вас всего несколько строк, а таблица <16K. (Например, при 4 строках средний размер строки возвращается как 4096). </p>

Дополнительные 6 байтов в строке для "невидимого" первичного ключа являются критической точкой, когда большое значение имеет пространство. Если в вашей таблице только один столбец, это идеальный столбец для создания первичного ключа, если предположить, что значения в нем уникальны:

CREATE TABLE `mytest2`
       (`num1` int(10) unsigned NOT NULL primary key)
ENGINE=InnoDB DEFAULT CHARSET=latin1;

Используя ПЕРВИЧНЫЙ КЛЮЧ, как это:

  1. Никакое предложение INDEX или KEY не требуется, потому что у вас нет вторичного индекса. Упорядоченный по индексу формат таблиц InnoDB обеспечивает быстрый быстрый поиск на основе значения первичного ключа бесплатно.
  2. Вы не получите другую копию данных столбца NUM1, что происходит, когда этот столбец индексируется явно.
  3. Вы не получите еще одну копию 6-байтовых значений невидимого первичного ключа. Значения первичного ключа дублируются в каждом вторичном индексе. (Это также причина, по которой вам, вероятно, не нужны 10 индексов для таблицы с 10 столбцами, и вам, вероятно, не нужен первичный ключ, который объединяет несколько различных столбцов или является столбцом длинной строки.)

Таким образом, в целом, использование только первичного ключа означает меньше данных, связанных с таблицей + индексы. Чтобы получить представление об общем размере данных, мне нравится работать с

set innodb_file_per_table = 1;

и проверьте размер файла data / database / * table * .ibd. Каждый файл .ibd содержит данные для таблицы InnoDB и все связанные с ней индексы.

Чтобы быстро создать большую таблицу для тестирования, я обычно запускаю следующую инструкцию:

insert into mytest
select * from mytest;

Что удваивает объем данных каждый раз. В случае таблицы с одним столбцом, использующей первичный ключ, поскольку значения должны были быть уникальными, я использовал вариант, чтобы значения не сталкивались друг с другом:

insert into mytest2
select num1 + (select count(*) from mytest2) from mytest2;

Таким образом, я смог уменьшить средний размер строки до 25. Служебные расходы основаны на базовом предположении, что вы хотите быстро найти отдельные строки с помощью механизма в стиле указателя, и большинство таблиц будет иметь столбец, значения которого служат указателями (т. е. первичным ключом) в дополнение к столбцам с реальными данными, которые суммируются, усредняются и отображаются.

1 голос
/ 27 мая 2010

В дополнение к очень хорошему ответу Quassnoi, вы, вероятно, должны попробовать его, используя значительный набор данных.

Что бы я сделал, загрузите 1М строк моделируемых производственных данных, затем измерьте размер таблицы и используйте это в качестве ориентира.

Это то, что Я все равно делал в прошлом

...