2016-01-07 3 views
0

Я создал приложение для отслеживания прогресса в Лига Легенд для меня и моих друзей. С этой целью я собираю информацию о текущем рейтинге несколько раз в день в моей базе данных 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) ,

+0

Пожалуйста, добавьте свое определение объекта сетки, поскольку это похоже на запрос или представление, а не только на таблицу, содержащую данные. Если это действительно таблица temp, добавьте схему и покажите, как вы ее заполняете. –

+0

@EsotericScreenName: добавлена ​​информация об этой таблице – MasterCassim

+0

В вашем запросе какое значение входит в параметр, где вы говорите «grid.series +?» Это то же самое, что и приращение, которое вы используете при создании таблицы сетки? Если это так, было бы лучше рассчитать второе число и сохранить его в самой таблице сетки, чтобы вы не использовали выражение в другом запросе. Кроме того, если таблица сетки довольно большая, вероятно, стоит добавить к ней индекс. Не может навредить. –

ответ

1

Задача 1 и решение

Вам нужна последовательность целых чисел, между двумя значениями? И они отличаются на 1? Или какой-то более высокой стоимостью?

Во-первых, создать постоянную таблицу чисел от 0 до некоторого достаточно большого значения:

CREATE TABLE Num10 (n INT); 
INSERT INTO Num10 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); 
CREATE TABLE Nums (n INT, PRIMARY KEY(n)) 
    SELECT a.n*1000 + b.n*100 + c.n*10 + d.n 
     FROM Num10 AS a 
     JOIN Num10 AS b -- note "cross join" 
     JOIN Num10 AS c 
     JOIN Num10 AS d; 

Теперь Nums имеет диапазоне 0..9999. (Сделать больше, если вы, возможно, потребуется больше.)

Чтобы получить последовательность последовательных чисел от 123 через 234:

SELECT 123 + n FROM Nums WHERE n < 234-123+1; 

Чтобы получить последовательность последовательных чисел от 12345 через 23456, с шагом 15 :

SELECT 12345 + 15*n FROM Nums WHERE n < (23456-12345+1)/15; 

JOIN к SELECT, как один из тех, кто вместо того, чтобы series_tmp.

Запрет других вопросов, которые должны значительно ускорить процесс.

Задача 2

Вы GROUPing BYseries, но ORDERing по timestamp. Они связаны, поэтому вы можете получить «правильный» ответ. Но подумай об этом.

Задача 3

Вы, кажется, строительство "ведра" (так называемые "серии"?) От "метки времени". Это верно? Если да, то давайте работать в обратном направлении - Превратить «метку» в «ведро» номер:

bucket_number = (timestamp - start)/bucket_size 

Делая это по всему, вы можете избежать «Проблема 1» и устранить мое решение. То есть, переформулируйте все запросы в терминах ведер.

+0

Спасибо за ваш ответ. Я изменил запрос в соответствии с вашим третьим предлагаемым решением (см. Выше). Есть еще проблема? – MasterCassim

+0

Наверное, работает нормально, как вы разместили в своем Редактировании. Попробуй это. –