Я работаю над схемой для аналитической системы, которая отслеживает время использования, и необходимо видеть общее время использования в определенном диапазоне дат.
Чтобы привести простой пример, этот тип запроса будет выполняться часто:
select sum(diff_ms) from writetest_table where time_on > ("2015-07-13 15:11:56");
Этот запрос обычно занимает около 7 секунд для таблицы с большим количеством пользователей. Он содержит ~ 35 миллионов строк, MyISAM на MySQL работает на Amazon RDS (db.m3.xlarge).
Избавление от предложения WHERE заставляет запрос занимать всего 4 секунды, а добавление второго предложения (time_off> XXX) добавляет дополнительные 1,5 секунды, в результате чего время запроса увеличивается до 8,5 секунд.
Поскольку я знаю, что эти типы запросов будут обычно выполняться, я бы хотел оптимизировать их, чтобы они выполнялись быстрее, в идеале - менее 5 секунд.
Я начал с добавления индекса для time_on, и, хотя это резко ускорило запрос WHERE "=", это не повлияло на запрос ">". Есть ли способ создать индекс, который ускорил бы запросы WHERE ">" или "<"?
Или, если есть какие-либо другие предложения о производительности этого типа запроса, пожалуйста, дайте мне знать.
Примечание: я использую поле "diff_ms" в качестве шага денормализации (оно равно time_off - time_on), что повышает производительность агрегации примерно на 30% -40%.
Я создаю индекс с помощью этой команды:
ALTER TABLE writetest_table ADD INDEX time_on (time_on) USING BTREE;
Выполнение «объяснения» в исходном запросе (с «time_on>») говорит, что time_on - это «возможный_ключ», а select_type - «ПРОСТОЙ». В столбце «extra» написано «Using where», а «type» - «ALL». После добавления индекса в таблице говорится, что «time_on» - это тип ключа «MUL», что кажется правильным, поскольку одно и то же время может присутствовать дважды.
Вот схема таблицы:
CREATE TABLE `writetest_table` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sessionID` int(11) DEFAULT NULL,
`time_on` timestamp NULL DEFAULT NULL,
`time_off` timestamp NULL DEFAULT NULL,
`diff_ms` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `time_on` (`time_on`)
) ENGINE=MyISAM AUTO_INCREMENT=50410902 DEFAULT CHARSET=latin1;
ОБНОВЛЕНИЕ: я создал следующий индекс на основе ответа ypercube, но это увеличивает время запроса для первого запроса примерно до 17 секунд!
ALTER TABLE writetest_table ADD INDEX time_on__diff_ms__ix (time_on, diff_ms) ;
ОБНОВЛЕНИЕ 2: ОБЪЯСНИТЕ вывод
mysql> explain select sum(diff_ms) from writetest_table where time_on > '2015-07-13 15:11:56';
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
| 1 | SIMPLE | writetest_table_old | index | time_on__diff_ms__ix | time_on__diff_ms__ix | 10 | NULL | 35831102 | Using where; Using index |
+----+-------------+---------------------+-------+----------------------+----------------------+---------+------+----------+--------------------------+
1 row in set (0.00 sec)
Обновление 3: результат запрошенного запроса
mysql> SELECT time_on FROM writetest_table ORDER BY time_on LIMIT 1;
+---------------------+
| time_on |
+---------------------+
| 2015-07-13 15:11:56 |
+---------------------+
1 row in set (0.01 sec)
time_on
иdiff_ms
)? Что произойдет, если вы добавите в запросWHERE ... AND diff_ms IS NOT NULL
?SELECT COUNT(*), COUNT(diff_ms) FROM writetest_table;
writetest_table_old
», в то время как запрос имеетfrom writetest_table
. Это опечатка или вы запускаете запрос в другой таблице?Ответы:
Я думаю, что начинаю понимать.
Когда я попросил тебя бежать
Вы сказали, что это было
2015-07-13 15:11:56
в вашейWHERE
статьеКогда вы сделали запрос
Было выполнено полное сканирование таблицы из 35,8 миллионов строк.
Когда вы сделали запрос
Было выполнено полное сканирование индекса в 35,8 миллионов строк.
Вполне понятно, что запрос без предложения WHERE выполняется быстрее. Почему ?
Сканирование таблицы будет считывать 35,8 миллиона строк за один линейный проход.
Объяснение запроса с WHERE также обнаружило 35,8 миллионов строк. Сканирование индекса будет вести себя немного иначе. Хотя BTREE следит за порядком клавиш, это ужасно для сканирования диапазона. В вашем конкретном случае вы выполняете сканирование наихудшего из возможных диапазонов, которое будет иметь такое же количество записей BTREE, как и строк в таблице. MySQL должен пройти страницы BTREE (по крайней мере через конечные узлы), чтобы прочитать значения. Кроме того,
time_on
столбец необходимо сравнивать по пути в порядке, определяемом индексом. Следовательно, неконечные узлы BTREE также должны быть пройдены.Пожалуйста, смотрите мои сообщения на BTREEs
Aug 06, 2013
: В MySQL, если столбец X имеет уникальные значения, в чем разница между индексом UNIQUE и индексом B-TreeJun 28, 2012
: Преимущества BTREE в MySQLЕсли запрос был по состоянию на полночь сегодня
или даже сегодня в полдень
это должно занять меньше времени.
МОРАЛЬ ИСТОРИИ. Не используйте предложение WHERE, которое выполняет сканирование в упорядоченном диапазоне, равное количеству строк в целевой таблице.
источник
Для конкретного запроса:
индекс на
(time_on, diff_ms)
будет лучшим вариантом. Итак, если запрос выполняется достаточно часто или его эффективность имеет решающее значение для вашего приложения, добавьте этот индекс:(Не относится к вопросу)
И действительно, измените движок таблицы на InnoDB. Это 2015 год, и похороны MyISAM были несколько лет назад.
(/ напыщенная)
источник
ALTER TABLE writetest_table DROP INDEX time_on;
, 2) выполнитьANALYZE TABLE writetest_table;
и 3) повторно выполнить запрос. Время возвращается к 7 секундам?EXPLAIN select sum(diff_ms) from writetest_table where time_on > ("2015-07-13 15:11:56");
. Используется ли новый индекс? Если он не используется, я бы сказал, что это ваша ключевая совокупность, особенно если ваш самый ранний time_on всего несколько дней назад. Поскольку число строк увеличивается с увеличением числа различных дней, распределение ключей должно выравниваться, и ОБЪЯСНЕНИЕ должно быть лучше ,