Есть база MySQL, таблица на InnoDB с парой-тройкой миллионов записей. Структура таблицы: id | server_id | bytes | date Из данных таблицы формируется статистика за промежутки времени следующим запросом: Code: SELECT server.name as name, m.count as minute, h.count as hour, d.count as day, w.count as week, 30d.count as thirty, overall.count as total, overall.date as updated FROM server LEFT JOIN (SELECT SUM(bytes) as count, server_id FROM traffic t WHERE date >= DATE_SUB(NOW(), INTERVAL 1 MINUTE) GROUP BY server_id) as m ON m.server_id = server.id LEFT JOIN (SELECT SUM(bytes) as count, server_id FROM traffic t WHERE date >= DATE_SUB(NOW(), INTERVAL 1 HOUR) GROUP BY server_id) h ON h.server_id = server.id LEFT JOIN (SELECT SUM(bytes) as count, server_id FROM traffic t WHERE date >= DATE_SUB(NOW(), INTERVAL 1 DAY) GROUP BY server_id) d ON d.server_id = server.id LEFT JOIN (SELECT SUM(bytes) as count, server_id FROM traffic t WHERE date >= DATE_SUB(NOW(), INTERVAL 1 WEEK) GROUP BY server_id) w ON w.server_id = server.id LEFT JOIN (SELECT SUM(bytes) as count, server_id, MAX(date) as date FROM traffic t WHERE date >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY server_id) 30d ON 30d.server_id = server.id LEFT JOIN (SELECT SUM(bytes) as count, , MAX(date) as date, server_id FROM traffic t GROUP BY server_id) overall ON overall.server_id = server.id ORDER BY name Видно, что запрос получается нагруженным из-за 6 сканирований одной таблицы. Вопрос: каким образом можно реализовать получение этих данных за 1-2 прохода по таблице traffic?
Первым делом стоит запустить explain http://dev.mysql.com/doc/refman/5.7/en/explain-output.html . Или запустить профилирование запроса https://habrahabr.ru/post/70435/ . Есть вариант, правда не совсем в него верю, но может помочь. Смысл в то что mysql не кэширует запросы с использованием NOW(), все left join'ы по факту работают с записями у которых where меньше определенной даты. Если заранее посчитать интервал DATE_SUB(NOW(), INTERVAL 30 DAY), например на PHP, то можно получить общий запрос (SELECT bytes, server_id, date FROM traffic t WHRE date >= $interval), и этот запрос уже попадет в кэш mysql. Далее на каждый LEFT JOIN вместо новой выборки, делаем выборку из кэшированного запроса: Code: (LEFT JOIN SELECT SUM(bytes) as count, server_id FROM (SELECT bytes, server_id, date FROM traffic t WHRE date >= $interval) WHERE date >=DATE_SUB(NOW(), INTERVAL 1 DAY) GROUP BY server_id) d ON d.server_id = server_.id (LEFT JOIN SELECT SUM(bytes) as count, server_id FROM (SELECT bytes, server_id, date FROM traffic t WHRE date >= $interval) WHERE date >=DATE_SUB(NOW(), INTERVAL 1 HOUR) GROUP BY server_id) h ON h.server_id = server_.id ..... Правда, повторюсь, это может только замедлить работу.