我已经为我和我的朋友创建了一个应用程序来跟踪英雄联盟的进度。为此,我每天多次将有关当前排名的信息收集到我的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秒),但我感谢任何通过重写或向数据库添加其他索引来改进查询的帮助。
/编辑:
在回顾了@Rick James的回答之后,我按如下方式修改了查询:
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 :(得分: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 BY
series
,ORDERing
是timestamp
。他们是相关的,所以你可能会得到正确的&#39;回答。但想一想。
问题3
你似乎正在建造#34;水桶&#34; (称为&#34;系列&#34;?)来自&#34;时间戳&#34;。它是否正确?如果是这样,让我们倒退 - 转一个&#34;时间戳&#34;进入&#34;桶&#34;号:
bucket_number = (timestamp - start) / bucket_size
通过这样做,您可以避免问题1&#39;并消除我的解决方案。也就是说,根据存储桶重新制定整个查询。