Я работаю над схемой для аналитической системы, которая отслеживает время использования, и необходимо видеть общее время использования в определенном диапазоне дат.
Чтобы привести простой пример, этот тип запроса будет выполняться часто:
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)
SELECT COUNT(*), COUNT(diff_ms) FROM writetest_table;
writetest_table_old
», в то время как запрос имеет from writetest_table
. Это опечатка или вы запускаете запрос в другой таблице?
time_on
иdiff_ms
)? Что произойдет, если вы добавите в запросWHERE ... AND diff_ms IS NOT NULL
?