Задавайте вопросы, мы ответим
Вы не зашли.
Приветствую, Коллеги!
Поможите в войне с индексами пожалуйста, кто чем может :-).
Имеется таблица
Отредактированно deadka (01.03.2011 16:14:48)
Неактивен
Мне очень нравится начало вопроса — «в табличке ~257млн записей»
Вопрос — почему оптимизатор делает то или иное — достаточно сложный.
Можешь посмотреть EXPLAIN EXTENDED от этой штуки и SHOW WARNINGS?
Есть ощущение, что оптимизатор делает сначала логическое упрощение
в (first BETWEEN ... ) AND (input = 10 OR output=10), а потом к нему ищет
индексы.
Запросы на OR-логику вообще очень тяжело рассматривать оптимизатору.
Например, если переписать запрос в виде UNION, он уже не ошибется в
выборе индексов. С другой стороны, кажется, план по сортированному объе-
динению индексов будет работать лучше, чем объединять сразу данные и
искать DISTINCT. Тут еще влияет то, что иногда прочитать больше строк с
диска последовательно оказывается более быстрым, чем вытащить строки
по индексу (+fileseek) и потом еще и посортировать в памяти.
Насильно указывать индексы, разумеется, стоит: именно для этого и служат
эти директивы. Человек всегда знает данные лучше, чем машина (точнее —
должен знать ), а потому должен корректировать машину, если она ошиба-
ется.
Да, индексы input и output — лишние при наличии input_2 и output_2.
Неактивен
Приветствую, paulus!, спасибо за ответ.
paulus написал:
Мне очень нравится начало вопроса — «в табличке ~257млн записей»
Ок, убедил, если очень приблизительно, то в табличке примерно 257413139 записей .
EXPLAIN EXTENDED совпало с explain, SHOW WARNINGS вернул пустую выборку.
С union все получилось, конечно.
Касательно насильственного указания индексов прошу уточнить - а как ему насильно указать, чтобы он использовал Using sort_union? Просто запретить использование индекса first ("ignore index(first)") и пусть сам разбирается, как ему использовать множественные индексы?
Или лучше прямо прописать use index(input_2,output_2)?
paulus написал:
Да, индексы input и output — лишние при наличии input_2 и output_2.
Да, конечно, просто в этой таблице изначально были одиночные индексы в том числе на input и output, а после я стал пытаться работать с множественными, дабы вышеуказанный запрос быстро работал .
Отредактированно deadka (10.03.2011 12:12:57)
Неактивен
Ээ... SHOW WARNINGS не может выдать пустую выборку после EXPLAIN EXTENDED.
Может быть, клиент накидал еще запросов между этими?
Да, заставить выбирать алгоритм нельзя, можно лишь влиять на порядок выборки
таблиц и индексов для них. С другой стороны, алгоритм обычно следует из индексов.
Неактивен
Да, это какие-то фокусы MySQL Workbench (насчёт пустой выборки от show warnings) , в консольном клиенте все показало.
Без насильственного указания индексов
mysql> explain extended SELECT sql_no_cache count(*) FROM `2011_03_04` where (input=10 and (first>='2011-03-04 00:00:00' and first<='2011-03-04 00:04:59')) or (output=10 and (first>='2011-03-04 00:00:00' and first<='2011-03-04 00:04:59'));
+----+-------------+------------+-------+---------------------------------------------+-------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------------------------------------+-------+---------+------+--------+-------------+
| 1 | SIMPLE | 2011_03_04 | range | first,input,output,input_first,output_first | first | 8 | NULL | 618561 | Using where |
+----+-------------+------------+-------+---------------------------------------------+-------+---------+------+--------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings\G
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: select sql_no_cache count(0) AS `count(*)` from `2011_03_04` where (((`2011_03_04`.`input` = 10) and (.`2011_03_04`.`first` >= _latin1'2011-03-04 00:00:00') and (.`2011_03_04`.`first` <= _latin1'2011-03-04 00:04:59')) or ((`2011_03_04`.`output` = 10) and (`2011_03_04`.`first` >= _latin1'2011-03-04 00:00:00') and (.`2011_03_04`.`first` <= _latin1'2011-03-04 00:04:59')))
1 row in set (0.00 sec)
С насильственным указанием
mysql> explain extended SELECT sql_no_cache count(*) FROM `2011_03_04` ignore index(first) where (input=10 and (first>='2011-03-04 00:00:00' and first<='2011-03-04 00:04:59')) or (output=10 and (first>='2011-03-04 00:00:00' and first<='2011-03-04 00:04:59'));
+----+-------------+------------+-------------+---------------------------------------+--------------------------+---------+------+-------+---------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------------+---------------------------------------+--------------------------+---------+------+-------+---------------------------------------------------------+
| 1 | SIMPLE | 2011_03_04 | index_merge | input,output,input_first,output_first | input_first,output_first | 9,9 | NULL | 57521 | Using sort_union(input_first,output_first); Using where |
+----+-------------+------------+-------------+---------------------------------------+--------------------------+---------+------+-------+---------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings\G
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: select sql_no_cache count(0) AS `count(*)` from `2011_03_04` IGNORE INDEX (`first`) where (((`2011_03_04`.`input` = 10) and (`2011_03_04`.`first` >= _latin1'2011-03-04 00:00:00') and (`2011_03_04`.`first` <= _latin1'2011-03-04 00:04:59')) or ((``2011_03_04`.`output` = 10) and (`2011_03_04`.`first` >= _latin1'2011-03-04 00:00:00') and (`2011_03_04`.`first` <= _latin1'2011-03-04 00:04:59')))
1 row in set (0.00 sec)
То же самое, но в профиль .
Неактивен
Да, оптимизатор ничего не выкинул. Ну, значит, тогда только указанием индексов
Неактивен