Простая проблема индексации MySQL - PullRequest
1 голос
/ 29 декабря 2011

У меня есть эта таблица:

CREATE TABLE IF NOT EXISTS `test1_nopart` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `idAccount` int(10) unsigned NOT NULL,
  `data` mediumint(8) unsigned NOT NULL,
  `date` date NOT NULL,
  PRIMARY KEY (`id`),
  KEY `date` (`date`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

Я заполняю эту таблицу 10 000 000 строк. Перераспределение по дате однородно

EXPLAIN SELECT * FROM `test1_nopart` WHERE date = "2014-03-04" 

Вот результат

id  select_type   table        type     possible_keys   key     key_len     ref     rows        Extra
1   SIMPLE     test1_nopart     ALL     NULL            NULL    NULL        NULL    7875981     Using where

=> без объяснения 3,6 с для результата 3000 строк (приблизительно)

Как вы можете видеть, индекс не используется и не является частью столбца возможных_ключей!

тот же запрос с указателем покрытия

EXPLAIN SELECT date FROM `test1_nopart` WHERE date = "2014-03-04"

результат:

id  select_type     table      type     possible_keys   key     key_len     ref     rows        Extra
1   SIMPLE       test1_nopart   index   NULL            date       3        NULL    7875981     Using where; Using index

=> без объяснения 2,8 с для результата 3000 строк (приблизительно)

Почему MySQL неправильно использует этот индекс (DATE) ???

Информация: - VM Server (наша среда разработки, я не знаю, каков состав оборудования) - MySQL 5.5.8

SHOW INDEX FROM test1_nopart

результат:

Table   Non_unique  Key_name    Seq_in_index    Column_name     Collation   Cardinality     Sub_part    Packed  Null    Index_type  Comment     Index_comment
test1_nopart    0   PRIMARY     1   id  A   7875981     NULL    NULL        BTREE        
test1_nopart    1   date    1   date    A   6077    NULL    NULL        BTREE        
  • На дату 2014-03-04 => 3134 строки
  • Итого (сведение) => 7 875 488
  • В таблице 2556 различных значений даты '1035 *

Ответы [ 4 ]

1 голос
/ 29 декабря 2011

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

Вам также может понадобиться посмотреть количество элементов в индексе и количество строк в каждом отдельном значении.

Выполните следующее:

SELECT COUNT(1) datecount,`date` FROM test1_nopart GROUP BY `date` WITH ROLLUP;

Согласно вашему комментарию, вы получите 6077 отдельных строк. Вы также сказали, что есть около 10 000 000 строк. Вместо этого запустите этот запрос:

SELECT COUNT(1) datecount FROM test1_nopart WHERE `date` = '2014-03-14';

Обратите внимание на количество и общее количество.

5% от 10 000 000 составляет 500 000

Если существует более 500 000 строк с датой «2014-03-14», MySQL никогда не будет правильно использовать индекс для этого конкретного значения.

Я не доверяю SHOW INDEXES FROM test1_nopart;, потому что таблица InnoDB. MyISAM покажет точное число. InnoDB производит числа, основанные на погружениях в указатель.

Если число дат какой-либо даты превышает 5% от общего числа строк, MySQL Query Optimizer поднимает руки и делает полное сканирование.

UPDATE

Хорошо, что 5% эмпирического правила за пределами окна Попробуйте обмануть MySQL Query Optimizer, создав другой индекс покрытия:

ALTER TABLE test1_nopart ADD INDEX date_id_ndx (`date`,id);

и попробуйте снова свои вопросы.

0 голосов
/ 30 декабря 2011

Это не проблема кардинальности.

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

https://stackoverflow.com/questions/8679940/primary-key-index-with-a-datetime-as-first-part-of-the-compound-key-is-never-use

Проблема возникла ТОЛЬКО в том случае, если первая клавиша является датой-временем ...

0 голосов
/ 29 декабря 2011

Вот мои мысли.

В первом случае, когда мы пытаемся получить data на date MySQL не использует индекс для date из-за очень низкой мощности.И оптимизатор использует следующее: - вторичный индекс - кластеризованный для доступа к строке - таблица для получения данных.

Во втором случае, когда мы пытаемся получить date на date, проще проходить через таблицу, используяindex, потому что MySQL также может извлекать выбранные данные из индекса (я имею в виду, что MySQL может сканировать только индекс вместо всей таблицы, чтобы получить те же данные).Используйте следующее: - вторичный индекс

0 голосов
/ 29 декабря 2011

Просто догадка - может быть, это как-то связано со словом date.

Попробуйте дать MySQL несколько подсказок, что вы хотите использовать это поле, а не зарезервированное слово:

SELECT date FROM `test1_nopart` WHERE `test1_nopart`.`date` = "2014-03-04"
...