Почему размер таблицы 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;

С помощью первичного ключа, как это:

  1. нет индекса или ключевого предложения не требуется, потому что у вас нет вторичного индекса. Индекс-организованный формат таблиц InnoDB дает вам быстрый поиск на основе значения первичного ключа бесплатно.
  2. вы не заканчиваете с другой копией данных столбца NUM1, что происходит, когда этот столбец индексируется явно.
  3. вы не заканчивайте с другой копией 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 строк моделируемых производственных данных, а затем измерить размер таблицы и использовать это в качестве руководства.

Что это Я сделал в прошлом в любом случае