Почему MySQL с InnoDB выполняет сканирование таблицы, когда ключ существует, и выбирает просмотреть в 70 раз больше строк? - PullRequest
3 голосов
/ 15 апреля 2010

Я устраняю проблему с производительностью запросов. Вот ожидаемый план запроса от объяснения:

mysql> explain select * from table1 where tdcol between '2010-04-13 00:00' and '2010-04-14 03:16';
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+
| id | select_type | table              | type  | possible_keys | key          | key_len | ref  | rows    | Extra       |
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+
|  1 | SIMPLE      | table1             | range | tdcol         | tdcol        | 8       | NULL | 5437848 | Using where | 
+----+-------------+--------------------+-------+---------------+--------------+---------+------+---------+-------------+
1 row in set (0.00 sec)

Это имеет смысл, поскольку используется индекс с именем tdcol (KEY tdcol (tdcol)), и в этом запросе должно быть выбрано около 5 миллионов строк.

Однако, если я запрашиваю еще одну минуту данных, мы получим план запроса:

mysql> explain select * from table1 where tdcol between '2010-04-13 00:00' and '2010-04-14 03:17';
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+
| id | select_type | table              | type | possible_keys | key  | key_len | ref  | rows      | Extra       |
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+
|  1 | SIMPLE      | table1             | ALL  | tdcol         | NULL | NULL    | NULL | 381601300 | Using where | 
+----+-------------+--------------------+------+---------------+------+---------+------+-----------+-------------+
1 row in set (0.00 sec)

Оптимизатор полагает, что сканирование будет лучше, но в нем проверяется более 70 раз больше строк, поэтому мне трудно поверить, что сканирование таблицы лучше.

Кроме того, синтаксис «USE KEY tdcol» не меняет план запроса.

Заранее благодарен за любую помощь, и я более чем рад предоставить больше информации / ответить на вопросы.

Ответы [ 4 ]

3 голосов
/ 15 апреля 2010

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

Этот случай может быть исключением, поскольку, вероятно, порядок меток времени примерно соответствует порядку вставок в таблицу. Но, если индекс tdcol не является «кластеризованным» индексом (это означает, что база данных гарантирует, что порядок в базовой таблице соответствует порядку в tdcol), маловероятно, что оптимизатор знает это.

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

0 голосов
/ 16 апреля 2010

"поэтому мне трудно поверить, что сканирование таблицы лучше."

True. ВЫ трудно поверить в это. Но оптимизатор, кажется, не.

Я не буду говорить о том, что вы «правы», а ваш оптимизатор «прав». Но оптимизаторы делают то, что делают, и, в целом, их «интеллектуальные» возможности все равно должны рассматриваться как довольно ограниченные.

Тем не менее, статистика вашей базы данных показывает значение MAX (для этого столбца), которое оказывается равным значению "на одну секунду больше"?

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

0 голосов
/ 15 апреля 2010

Как выглядит распределение ваших данных?Попробуйте запустить min (), avg (), max (), чтобы увидеть, где он находится.Вполне возможно, что эта 1 минута влияет на количество информации, содержащейся в этом диапазоне.

Это также может быть просто фоновая настройка InnoDB. Есть несколько факторов, таких как размер страницы и объем памяти, как говорит staticsan.Вы можете явно определить индекс B + Tree.

0 голосов
/ 15 апреля 2010

Генератор запросов MySQL имеет обрезание при выяснении, как использовать индекс. Как вы правильно определили, MySQL решила, что сканирование таблицы будет проходить быстрее, чем при использовании индекса, и не будет отговорено от его решения. Ирония в том, что когда диапазон клавиш соответствует более трети таблицы, это, вероятно, правильно. Так почему в этом случае?

У меня нет ответа, но у меня есть подозрение, что у MySQL недостаточно памяти для исследования индекса. Я хотел бы посмотреть на настройки памяти сервера, в частности пул памяти Innodb и некоторые другие ключевые пулы хранения.

...