Почему размер таблицы InnoDB намного больше, чем ожидалось?
Я пытаюсь выяснить требования к памяти для различных систем хранения. У меня есть такая таблица:
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-байтовый unsigned int?
3 ответов
InnoDB
таблицы кластеризованы, это означает, что все данные содержатся в B-Tree
С PRIMARY KEY
в качестве ключа и всех других столбцов в качестве полезной нагрузки.
так как вы не определяете явное PRIMARY KEY
, InnoDB
использует скрытый 6-байтовый столбец для сортировки записей.
это и накладные расходы B-Tree
организация (с дополнительными блоками не-листового уровня) требует больше места, чем sizeof(int) * num_rows
.
вот еще информация, которую вы можете найти полезной.
InnoDB выделяет данные в терминах страниц 16KB, поэтому "показать состояние таблицы" даст завышенные номера для размера строки, Если у вас есть только несколько строк, а таблица
дополнительные 6 байт в строке для "невидимого" первичного ключа являются решающим моментом, когда пространство является большим соображением. Если ваша таблица является только одним столбцом, это идеальный столбец для сделать первичный ключ, предполагая, что значения в нем не повторяются:
CREATE TABLE `mytest2`
(`num1` int(10) unsigned NOT NULL primary key)
ENGINE=InnoDB DEFAULT CHARSET=latin1;
С помощью первичного ключа, как это:
- нет индекса или ключевого предложения не требуется, потому что у вас нет вторичного индекса. Индекс-организованный формат таблиц InnoDB дает вам быстрый поиск на основе значения первичного ключа бесплатно.
- вы не заканчиваете с другой копией данных столбца NUM1, что происходит, когда этот столбец индексируется явно.
- вы не заканчивайте с другой копией 6-байтовых невидимых значений первичного ключа. Значения первичного ключа дублируются в каждом вторичном индексе. (Это также причина, по которой вы, вероятно, не хотите 10 индексов в таблице с 10 столбцами, и вы, вероятно, не хотите первичный ключ, который объединяет несколько разных столбцов или является столбцом длинной строки.)
таким образом, в целом, придерживаться только первичного ключа означает меньше данных, связанных с индексами table+. Чтобы понять общие данные размер, мне нравится работать с
set innodb_file_per_table = 1;
и изучить размер данных/база данных/*стол*.файлы ibd. Каждый.файл ibd содержит данные для таблицы InnoDB и всех связанных с ней индексов.
чтобы быстро создать большую таблицу для тестирования, я обычно запускаю оператор так:
insert into mytest
select * from mytest;
, который удваивает количество данных каждый раз. В случае таблицы с одним столбцом, использующей первичный ключ, поскольку значения должны быть уникальными, я использовал вариант чтобы значения не сталкивались друг с другом:
insert into mytest2
select num1 + (select count(*) from mytest2) from mytest2;
таким образом, я смог получить средний размер строки до 25. Накладные расходы пространства основаны на базовом предположении, что вы хотите иметь быстрый поиск для отдельных строк с помощью механизма стиля указателя, и большинство таблиц будут иметь столбец, значения которого служат указателями (т. е. первичным ключом) в дополнение к столбцам с реальными данными, которые суммируются, усредняются и отображаются.
в дополнение к очень тонкому ответу Quassnoi, вы, вероятно, должны попробовать его, используя значительный набор данных.
Что я бы сделал, это загрузить 1M строк моделируемых производственных данных, а затем измерить размер таблицы и использовать это в качестве руководства.