Я создал приложение для отслеживания прогресса в Лига Легенд для меня и моих друзей. С этой целью я собираю информацию о текущем рейтинге несколько раз в день в моей базе данных MySQL. Для того, чтобы принести результаты и показать их на графике, я использую следующий запрос/запросы:Индекс запросов и улучшения запросов MySQL
SELECT
lol_summoner.name as name, grid.series + ? as timestamp,
AVG(NULLIF(lol.points, 0)) as points
FROM
series_tmp grid
JOIN
lol ON lol.timestamp >= grid.series AND lol.timestamp < grid.series + ?
JOIN
lol_summoner ON lol.summoner = lol_summoner.id
GROUP BY
lol_summoner.name, grid.series
ORDER BY
name, timestamp ASC
SELECT
lol_summoner.name as name, grid.series + ? as timestamp,
AVG(NULLIF(lol.points, 0)) as points
FROM
series_tmp grid
JOIN
lol ON lol.timestamp >= grid.series AND lol.timestamp < grid.series + ?
JOIN
lol_summoner ON lol.summoner = lol_summoner.id
WHERE
lol_summoner.name IN (". str_repeat('?, ', count($names) - 1) ."?)
GROUP BY
lol_summoner.name, grid.series
ORDER BY
name, timestamp ASC
Первый запрос используется в случае, если я хочу, чтобы получить все игроки, которые сохраняются в базе данных. Таблица сетки представляет собой временную таблицу, которая генерирует временные метки в определенный интервал для извлечения информации в кусках этого интервала. Две переменные в этом запросе - это интервал. Второй запрос используется, если я хочу получать информацию только для определенных игроков.
В таблице сетки производит по следующей хранимой процедуре, которая вызывается с тремя параметрами (n_first - первый временной метки, n_last - последняя временной метки, n_increments - с шагом между двумя временными метками):
BEGIN
-- Create tmp table
DROP TEMPORARY TABLE IF EXISTS series_tmp;
CREATE TEMPORARY TABLE series_tmp (
series bigint
) engine = memory;
WHILE n_first <= n_last DO
-- Insert in tmp table
INSERT INTO series_tmp (series) VALUES (n_first);
-- Increment value by one
SET n_first = n_first + n_increment;
END WHILE;
END
Запрос работает и заканчивается в разумные сроки (~ 10 секунд), но я благодарен за любую помощь в улучшении запроса путем его перезаписи или добавления дополнительных индексов в базу данных.
/Edit:
После рассмотрения @Rick Джеймс ответа, я изменил запросы следующим образом:
SELECT lol_summoner.name as name, (lol.timestamp div :range) * :range + :half_range as timestamp, AVG(NULLIF(lol.points, 0)) as points
FROM lol
JOIN lol_summoner ON lol.summoner = lol_summoner.id
GROUP by lol_summoner.name, lol.timestamp div :range
ORDER by name, timestamp ASC
SELECT lol_summoner.name as name, (lol.timestamp div :range) * :range + :half_range as timestamp, AVG(NULLIF(lol.points, 0)) as points
FROM lol
JOIN lol_summoner ON lol.summoner = lol_summoner.id
WHERE lol_summoner.name IN (<NAMES>)
GROUP by lol_summoner.name, lol.timestamp div " . $steps . "
ORDER by name, timestamp ASC
Это уменьшает время выполнения запроса по действительно хорошим запасом (законченный путь под 1s) ,
Пожалуйста, добавьте свое определение объекта сетки, поскольку это похоже на запрос или представление, а не только на таблицу, содержащую данные. Если это действительно таблица temp, добавьте схему и покажите, как вы ее заполняете. –
@EsotericScreenName: добавлена информация об этой таблице – MasterCassim
В вашем запросе какое значение входит в параметр, где вы говорите «grid.series +?» Это то же самое, что и приращение, которое вы используете при создании таблицы сетки? Если это так, было бы лучше рассчитать второе число и сохранить его в самой таблице сетки, чтобы вы не использовали выражение в другом запросе. Кроме того, если таблица сетки довольно большая, вероятно, стоит добавить к ней индекс. Не может навредить. –