SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 20.06.2011 19:50:34

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

зависимость размера индекса от его cardinality

Коллеги, тут некоторые вопросы по индексам возникли.

Вопрос № 1: ведет ли снижение количества уникальных значений, хранящихся в столбце, к уменьшению размера индекса по этому столбцу? (если да, то почему?)

Вопрос № 2: правда ли, что в индексе хранятся только уникальные значения? Другими словами, если в таблице 60 записей с одним и тем же значением проиндексированного столбца, то в индексе будет одна запись, а не 60?

Вопросы эти навеяны ситуацией из жизни: есть таблица ~1M записей, в ней — колонка типа TIMESTAMP, на которой простой индекс.

Была создана тестовая таблица с такой же структурой, куда были вставлены записи с точностью до минуты (т.е. DATE_FORMAT(column,
'%Y-%m-%d %H:%i') — получилось, что в секундах всегда нули).
Результат — уменьшение объема индекса в 2.3 раза.

Отсюда вопрос № 3: почему именно в 2.3, а не в 60, например?
(что касается распределения значений: оно соответствует активности в интернете в течение суток (хранится посещаемость сайта в реальном времени за сутки), т.е. когда-то записей побольше, когда-то — поменьше (интенсивность в минуту может отличаться где-то на порядок), но в любом случае каждую секунду как минимум несколько записей есть).

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

Поэтому вопрос № 4: как полученный результат согласуется с примером для вопроса № 3? Почему в одном случае уменьшение объема индекса было зафиксировано, а в другом — нет?

Ниже привожу код SQL-запросов, которыми я пользовался для получения результата:


CREATE TABLE  ts_different (
    t TIMESTAMP NOT NULL,
    KEY (t)
);

CREATE TABLE ts_same LIKE ts_different;


-- сначала заполняем одинаковыми значениями

INSERT INTO ts_same VALUES (NOW());

INSERT INTO ts_same SELECT * FROM ts_same;

-- (я повторял, пока не стало 2048 записей)

OPTIMIZE TABLE ts_same;


-- теперь заполняем разными

SET @i = 0;

INSERT INTO ts_different
SELECT DATE_ADD(t, INTERVAL @i := @i + 1 SECOND)
FROM ts_same;

OPTIMIZE TABLE ts_different;
 


Код:

mysql> SHOW TABLE STATUS LIKE 'ts%'\G
*************************** 1. row ***************************
           Name: ts_different
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 2048
 Avg_row_length: 7
    Data_length: 14336
Max_data_length: 1970324836974591
   Index_length: 23552
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-20 17:47:32
    Update_time: 2011-06-20 17:58:07
     Check_time: 2011-06-20 17:58:07
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
*************************** 2. row ***************************
           Name: ts_same
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 2048
 Avg_row_length: 7
    Data_length: 14336
Max_data_length: 1970324836974591
   Index_length: 23552
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-20 17:49:12
    Update_time: 2011-06-20 17:50:47
     Check_time: 2011-06-20 17:51:09
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
2 rows in set (0.02 sec)

(пробовал воспроизводить также, делая таблицы со значениями с точностью до минуты (т.е. с нулями в секундах), с одинаковыми и с разными — получалось то же самое).

Неактивен

 

#2 21.06.2011 00:33:14

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: зависимость размера индекса от его cardinality

Если значения одинаковые, то им в индексе соответствует одна вершина, в которой список ссылок на строки. То есть экономится количество вершин и связей между ними, что грубо соответствует примерно половине объема. 2048 записей это, возможно, мало для теста - попробуй больше. Кстати, в different значения получаются не все разные - некоторые все равно совпадают.

Неактивен

 

#3 21.06.2011 01:22:39

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: зависимость размера индекса от его cardinality

Если значения одинаковые, то им в индексе соответствует одна вершина, в которой список ссылок на строки. То есть экономится количество вершин и связей между ними, что грубо соответствует примерно половине объема.

Ага, ну тогда понятно. Значит, 2.3 раза - это и есть эта разница.

Получается, внимательный подход к требуемой гранулярности данных может обеспечить заметную оптимизацию (это хорошо, что индекс не очень большой; если бы был несколько Гб — этот аспект сыграл бы важную роль).
То есть, при прочих равных условиях следует стремиться к низкой carinality индекса (если это согласуется с потребностями запросов, используемых в приложении).

Кстати, где лучше почитать про принципы организации индекса?

2048 записей это, возможно, мало для теста - попробуй больше.

Сделал на миллион. Отличия исчезающе малы:

Код:

mysql> SELECT COUNT(DISTINCT(t)) FROM ts_same;
+--------------------+
| COUNT(DISTINCT(t)) |
+--------------------+
|                  1 |
+--------------------+
1 row in set (0.00 sec)

mysql> SELECT COUNT(DISTINCT(t)) FROM ts_different;
+--------------------+
| COUNT(DISTINCT(t)) |
+--------------------+
|            1048576 |
+--------------------+
1 row in set (0.36 sec)

mysql> SHOW TABLE STATUS:
           Name: ts_same
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 1048576
 Avg_row_length: 7
    Data_length: 7340032
Max_data_length: 1970324836974591
   Index_length: 10779648
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-20 18:21:10
    Update_time: 2011-06-20 18:22:16
     Check_time: 2011-06-20 18:22:37
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

           Name: ts_different
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 1048576
 Avg_row_length: 7
    Data_length: 7340032
Max_data_length: 1970324836974591
   Index_length: 10700800
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-21 01:00:59
    Update_time: 2011-06-21 01:01:44
     Check_time: 2011-06-21 01:01:55
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:

Странно, почему в этом случае нет выигрыша?
У меня была идея, что, возможно, т.к. в таблице, кроме проиндексированной, колонок больше нет, поэтому я ради эксперимента добавил в таблицы колонку.
Результат меня удивляет, т.к. в результате не изменилась не только длина индекса, но и Data length!

Код:

ALTER TABLE ts_same ADD COLUMN filler NOT NULL DEFAULT 0;

ALTER TABLE ts_different ADD COLUMN filler NOT NULL DEFAULT 0;

OPTIMIZE TABLE ts_same;

OPTIMIZE TABLE ts_different;

-- ни объем данных, ни объем индекса заметно не изменились:

mysql> SHOW TABLE STATUS LIKE 'ts%'\G
*************************** 1. row ***************************
           Name: ts_different
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 1048576
 Avg_row_length: 7
    Data_length: 7340032
Max_data_length: 1970324836974591
   Index_length: 10823680
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-21 01:14:38
    Update_time: 2011-06-21 01:18:15
     Check_time: 2011-06-21 01:18:15
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
*************************** 2. row ***************************
           Name: ts_same
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 1048576
 Avg_row_length: 7
    Data_length: 7340032
Max_data_length: 1970324836974591
   Index_length: 10762240
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-21 01:14:30
    Update_time: 2011-06-21 01:18:09
     Check_time: 2011-06-21 01:18:09
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:

Кстати. Интересно, почему показывается Avg_row_length = 7 байт? И такая же показывалась, когда одна колонка была. Ведь TIMESTAMP NOT NULL 4 байта занимает, а не 7.

Неактивен

 

#4 21.06.2011 07:36:12

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: зависимость размера индекса от его cardinality

У тебя ведь есть таблица, у которой индекс стал в 2.3 раза меньше. Попробуй ее искусственно воссоздать (с ровно такой же структурой). Насчет 7 байт это может быть следствие какого-то выравнивания в памяти или на диске (странно конечно, так как ожидалась степень двойки) - добавь еще колонок, 7 байт не останется.

Прочитать про деревья:
а) JAVA-демонстрация http://people.ksp.sk/~kuko/bak/index.html
б) http://en.wikipedia.org/wiki/B-tree
в) Никлаус Вирт, Алгоритмы и структуры данных, 2011 (в книге есть даже простой код реализации осеновных типов деревьев)

Неактивен

 

#5 23.06.2011 07:48:43

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: зависимость размера индекса от его cardinality

У тебя ведь есть таблица, у которой индекс стал в 2.3 раза меньше. Попробуй ее искусственно воссоздать (с ровно такой же структурой).

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

(рабочая таблица не сильно и отличается: там всего два столбца других есть, вида INT NOT NULL; ну и побольше она - где-то 1.6M записей; хотя я с миллионом и на тестовой пробовал.. фигня какая-то непонятная, короче)

Неактивен

 

#6 23.06.2011 07:52:00

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: зависимость размера индекса от его cardinality

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

Неактивен

 

#7 25.06.2011 00:11:08

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: зависимость размера индекса от его cardinality

Кажется, нашёл, где собака зарыта: в механизмах хранения!

Таблицы в MyISAM показывают одинаковые размеры индекса, тогда как таблицы в InnoDB - разные (это уже тест с реальных данных).

Выходит, дело в InnoDB, а не в механизме построения B-Tree? yikes

Отсюда вопрос: почему в случае MyISAM нет выигрыша в объеме ключа от снижения количества уникальных значений, а в InnoDB есть, при том, что и в том, и в том случае используется механизм B-Tree?
Имеет ли в таком случае наблюдаемое снижение объема ключа для InnoDB отношение к самому механизму B-Tree?

(насчет InnoDB и его неявного первичного ключа: пробовал добавлять первичный ключ в таблицы; это не приводило ни к увеличению объема данных таблиц, ни к увеличению длины индекса (что является хорошей иллюстрацией того, как в InnoDB неявно создается первичный ключ), но соотношение размеров индекса у таблицы с округленными секундами и с неокругленными сохранилось; т.е. разность в размерах индекса у InnoDB к первичному ключу, видимо, отношения не имеет)

Ниже привожу данные тестов:

Код:

mysql> SHOW TABLE STATUS LIKE '%'\G
... -- тут еще другая таблица была, поэтому 2.row
*************************** 2. row ***************************
           Name: innodb_00sec
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1673430
 Avg_row_length: 39
    Data_length: 66682880
Max_data_length: 0
   Index_length: 35209216
      Data_free: 37748736
 Auto_increment: NULL
    Create_time: 2011-06-24 23:25:33
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 3. row ***************************
           Name: innodb_different
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1673430
 Avg_row_length: 39
    Data_length: 66682880
Max_data_length: 0
   Index_length: 82444288
      Data_free: 37748736
 Auto_increment: NULL
    Create_time: 2011-06-24 23:27:17
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 4. row ***************************
           Name: myisam_00sec
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 17071104
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-24 23:25:06
    Update_time: 2011-06-24 23:30:40
     Check_time: 2011-06-24 23:25:33
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 5. row ***************************
           Name: myisam_different
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 17071104
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-24 23:27:00
    Update_time: 2011-06-24 23:30:40
     Check_time: 2011-06-24 23:27:17
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:

Код:

mysql> SELECT COUNT(DISTINCT(DATE)) FROM innodb_00sec;
+-----------------------+
| COUNT(DISTINCT(DATE)) |
+-----------------------+
|                  1448 |
+-----------------------+
1 row in set (5.19 sec)

mysql> SELECT COUNT(DISTINCT(DATE)) FROM innodb_different;
+-----------------------+
| COUNT(DISTINCT(DATE)) |
+-----------------------+
|                 83881 |
+-----------------------+
1 row in set (8.66 sec)

mysql> SELECT COUNT(DISTINCT(DATE)) FROM myisam_different;
+-----------------------+
| COUNT(DISTINCT(DATE)) |
+-----------------------+
|                 83881 |
+-----------------------+
1 row in set (0.00 sec)

mysql> SELECT COUNT(DISTINCT(DATE)) FROM myisam_00sec;
+-----------------------+
| COUNT(DISTINCT(DATE)) |
+-----------------------+
|                  1448 |
+-----------------------+
1 row in set (0.00 sec)

Структура всех четырех таблиц идентична:

Код:

mysql> SHOW CREATE TABLE innodb_different\G
*************************** 1. row ***************************
       Table: innodb_different
Create Table: CREATE TABLE `innodb_different` (
  `siteid` int(10) unsigned NOT NULL,
  `pageid` int(10) unsigned NOT NULL,
  `DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY `DATE` (`DATE`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC

Неактивен

 

#8 25.06.2011 10:13:55

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: зависимость размера индекса от его cardinality

А я думал MyISAM и используетсся, так как все таблицы в теме были MyISAM. В InnoDB другая реализация B-tree, возможно более эффективная. Попробуй сконвертить обе таблицы в MyISAM - какой будет размер индекса?

Неактивен

 

#9 26.06.2011 06:24:46

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: зависимость размера индекса от его cardinality

А я думал MyISAM и используетсся, так как все таблицы в теме были MyISAM.

Я сначала сделал тестовые таблицы в MyISAM, т.к. думал, что механизм хранения не влияет на размер индекса.
Рабочие таблицы были в InnoDB.

InnoDB другая реализация B-tree, возможно более эффективная.

В смысле, больше по объему, но быстрее работает?
То, что больше по объему - это точно.
Для сравнения я сделал таблицы в MyISAM, куда добавил первичный ключ (чтобы покрыть разницу с неявным первичным ключом в InnoDB).
Все равно в MyISAM длина ключей меньше в два раза минимум:

Код:

mysql> SHOW TABLE STATUS LIKE '%_with_pk'\G
*************************** 1. row ***************************
           Name: innodb_00sec_with_pk
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1673604
 Avg_row_length: 37
    Data_length: 62472192
Max_data_length: 0
   Index_length: 30998528
      Data_free: 115343360
 Auto_increment: 1673652
    Create_time: 2011-06-24 23:55:16
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 2. row ***************************
           Name: innodb_different_with_pk
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1673604
 Avg_row_length: 37
    Data_length: 62472192
Max_data_length: 0
   Index_length: 81379328
      Data_free: 115343360
 Auto_increment: 1673534
    Create_time: 2011-06-24 23:41:01
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 3. row ***************************
           Name: myisam_00sec_with_pk
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 34267136
      Data_free: 0
 Auto_increment: 1673094
    Create_time: 2011-06-26 06:20:23
    Update_time: 2011-06-26 06:20:23
     Check_time: 2011-06-26 06:22:59
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 4. row ***************************
           Name: myisam_different_with_pk
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 34267136
      Data_free: 0
 Auto_increment: 1673094
    Create_time: 2011-06-26 06:20:15
    Update_time: 2011-06-26 06:20:15
     Check_time: 2011-06-26 06:22:15
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
4 rows in set (0.50 sec)

попробуй сконвертить обе таблицы в MyISAM - какой будет размер индекса?

Так я уже попробовал — см. предыдущий пост.
Результат: у обех таблиц MyISAM объем индекса и объем данных одинаковый (посмотри SHOW TABLE STATUS в предыдущем моем посте — там все показано).

Неактивен

 

#10 26.06.2011 10:16:29

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: зависимость размера индекса от его cardinality

LazY написал:

Я сначала сделал тестовые таблицы в MyISAM, т.к. думал, что механизм хранения не влияет на размер индекса.

Это очень сильное допущение. MyISAM и InnoDB с точки зрения физического представления - две разные базы данных.

Я хотел увидеть сравнение MyISAM и Innodb. То есть 4 размера индексов: MyISAM_different, MyISAM_same, InnoDB_different, InnoDB_same. При этом нужно первичный ключ создать явно и для MyISAM и для InnoDB одного и того же типа. InnoDB во вторичном ключе хранит ссылку на первичный ключ - по умолчанию он 6 байт.

Неактивен

 

#11 27.06.2011 01:43:23

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: зависимость размера индекса от его cardinality

Я хотел увидеть сравнение MyISAM и Innodb. То есть 4 размера индексов: MyISAM_different, MyISAM_same, InnoDB_different, InnoDB_same.

Я ж говорю, в том сообщении было.
Ну ладно, запощу еще раз:

Код:

*************************** 2. row ***************************
           Name: innodb_00sec
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1673430
 Avg_row_length: 39
    Data_length: 66682880
Max_data_length: 0
   Index_length: 35209216
      Data_free: 37748736
 Auto_increment: NULL
    Create_time: 2011-06-24 23:25:33
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 3. row ***************************
           Name: innodb_different
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1673430
 Avg_row_length: 39
    Data_length: 66682880
Max_data_length: 0
   Index_length: 82444288
      Data_free: 37748736
 Auto_increment: NULL
    Create_time: 2011-06-24 23:27:17
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 4. row ***************************
           Name: myisam_00sec
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 17071104
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-24 23:25:06
    Update_time: 2011-06-24 23:30:40
     Check_time: 2011-06-24 23:25:33
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 5. row ***************************
           Name: myisam_different
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 17071104
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-24 23:27:00
    Update_time: 2011-06-24 23:30:40
     Check_time: 2011-06-24 23:27:17
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:

При этом нужно первичный ключ создать явно и для MyISAM и для InnoDB одного и того же типа.

Ок, привожу таблицы с явным первичным ключом:

Код:

mysql> SHOW CREATE TABLE innodb_00sec_with_pk\G
*************************** 1. row ***************************
       Table: innodb_00sec_with_pk
Create Table: CREATE TABLE `innodb_00sec_with_pk` (
  `siteid` int(10) unsigned NOT NULL,
  `pageid` int(10) unsigned NOT NULL,
  `DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  KEY `DATE` (`DATE`)
) ENGINE=InnoDB AUTO_INCREMENT=1673652 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
1 row in set (0.02 sec)

(структура остальных трех таблиц идентична)

TABLE STATUS для четырех таблиц с первичным ключом:

Код:

*************************** 1. row ***************************
           Name: innodb_00sec_with_pk
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1673604
 Avg_row_length: 37
    Data_length: 62472192
Max_data_length: 0
   Index_length: 30998528
      Data_free: 115343360
 Auto_increment: 1673652
    Create_time: 2011-06-24 23:55:16
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 2. row ***************************
           Name: innodb_different_with_pk
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1673604
 Avg_row_length: 37
    Data_length: 62472192
Max_data_length: 0
   Index_length: 81379328
      Data_free: 115343360
 Auto_increment: 1673534
    Create_time: 2011-06-24 23:41:01
    Update_time: NULL
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 3. row ***************************
           Name: myisam_00sec_with_pk
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 34267136
      Data_free: 0
 Auto_increment: 1673094
    Create_time: 2011-06-26 06:20:23
    Update_time: 2011-06-26 06:37:48
     Check_time: 2011-06-26 06:22:59
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:
*************************** 4. row ***************************
           Name: myisam_different_with_pk
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 34267136
      Data_free: 0
 Auto_increment: 1673094
    Create_time: 2011-06-26 06:20:15
    Update_time: 2011-06-26 06:37:48
     Check_time: 2011-06-26 06:22:15
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:

Чего не могу понять - так это снова странные значения Avg_row_length. Откуда 20 байт вместо 16 для MyISAM и 37 для InnoDB? yikes

Неактивен

 

#12 27.06.2011 15:40:01

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: зависимость размера индекса от его cardinality

Получается, что для 00 sec, индекс InnoDB занимает на 10% меньше, чем MyISAM. Просто разные алгоритмы хранения, поэтому размер и поведение разное.

20 байт может быть из-за row_format=DYNAMIC, попробуй переделать на FIXED. InnoDB оставляет место под row-based блокировки и информацию о версиях данных, поэтому ничего от Avg_row_length ожидать не стоит.

Неактивен

 

#13 27.06.2011 15:59:14

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: зависимость размера индекса от его cardinality

Есть ощущение, что PK считается в случае InnoDB в Data_length (из-за хранения
данных на листьях), а в MyISAM — в Index_length.

Неактивен

 

#14 27.06.2011 16:20:05

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: зависимость размера индекса от его cardinality

Все равно непонятно, откуда 20 байт в MyISAM, хотя должно быть 4 * 4 = 16 (везде INT NOT NULL или TIMESTAMP NOT NULL)

Неактивен

 

#15 27.06.2011 16:34:20

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: зависимость размера индекса от его cardinality

+1 байт служебный. Создал такую таблицу c row_format=dynamic - все получилось как ожидалось 17 байт. Для row_format=dynamic получается 20 байт, видимо 3 байта отводится на длину строки. Ты как создаешь таблицы? По умолчанию MyISAM таблицы такого типа создаются с row_format=fixed.


CREATE TABLE `diff` (
  `siteid` int(10) unsigned NOT NULL,
  `pageid` int(10) unsigned NOT NULL,
  `DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  KEY `DATE` (`DATE`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=latin1


mysql> show table status like 'diff'\G
*************************** 1. row ***************************
           Name: diff
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 2
 Avg_row_length: 17
    Data_length: 34
Max_data_length: 4785074604081151
   Index_length: 3072
      Data_free: 0
 Auto_increment: 5
    Create_time: 2011-06-27 16:28:36
    Update_time: 2011-06-27 16:28:59
     Check_time: NULL
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

Неактивен

 

#16 03.07.2011 06:02:41

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: зависимость размера индекса от его cardinality

Да, был Row format: Dynamic.

Только вот непонятны две вещи:

1. Почему у MyISAM-таблицы с одной NOT-NULL колонкой на 4 байта получатся Avg row length: 7  (cм. пример из головного сообщения):

Код:

CREATE TABLE  ts_different (
    t TIMESTAMP NOT NULL,
    KEY (t)
);

mysql> SHOW TABLE STATUS LIKE 'ts%'\G
*************************** 1. row ***************************
           Name: ts_different
         Engine: MyISAM
        Version: 10
     Row_format: Fixed
           Rows: 2048
 Avg_row_length: 7
    Data_length: 14336
Max_data_length: 1970324836974591
   Index_length: 23552
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-20 17:47:32
    Update_time: 2011-06-20 17:58:07
     Check_time: 2011-06-20 17:58:07
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:

2. (вот это уж совсем странно)
Еще раз щас посмотрел тестовые таблицы. Так вот. Там 20 байт на запись и 3(!) колонки (не 4). Должно быть 4*3 + 1 + 3 = 16 байт.
Не понимаю.. yikes

Код:

mysql> SHOW CREATE TABLE hits_bak1_myisam\G
*************************** 1. row ***************************
       Table: hits_bak1_myisam
Create Table: CREATE TABLE `hits_bak1_myisam` (
  `siteid` int(10) unsigned NOT NULL,
  `pageid` int(10) unsigned NOT NULL,
  `DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY `DATE` (`DATE`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC

mysql> SHOW TABLE STATUS LIKE 'hits%_myisam'\G
*************************** 1. row ***************************
           Name: hits_bak1_myisam
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1673093
 Avg_row_length: 20
    Data_length: 33461860
Max_data_length: 281474976710655
   Index_length: 17071104
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2011-06-27 02:43:02
    Update_time: 2011-06-27 02:43:24
     Check_time: 2011-06-27 02:43:26
      Collation: latin1_swedish_ci
       Checksum: NULL
 Create_options: row_format=DYNAMIC
        Comment:

Неактивен

 

#17 03.07.2011 11:14:12

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: зависимость размера индекса от его cardinality

7 байт это похоже минимум для fixed. Про dynamic я не знаю как рассчитывать объем - могут быть свои особенности.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson