首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MySQL查询索引及性能改进

MySQL查询索引及性能改进
EN

Stack Overflow用户
提问于 2016-01-07 14:25:21
回答 1查看 62关注 0票数 0

我为我和我的朋友创建了一个应用程序来跟踪英雄联盟的进度。为此,我每天在MySQL数据库中多次收集有关当前级别的信息。为了获取结果并在图中显示结果,我使用以下查询/查询:

代码语言:javascript
运行
复制
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 -两个时间戳之间的增量):

代码语言:javascript
运行
复制
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的答案之后,我将查询修改如下:

代码语言:javascript
运行
复制
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以下完成)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-07 17:41:24

问题1与解

你需要两个值之间的一系列整数吗?他们的差别是1?还是更大的价值?

首先,创建一个数字从0到足够大的值的永久表:

代码语言:javascript
运行
复制
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的连续数字序列:

代码语言:javascript
运行
复制
 SELECT 123 + n FROM Nums WHERE n < 234-123+1;

要获得从12345到23456的连续数字序列,步骤为15:

代码语言:javascript
运行
复制
 SELECT 12345 + 15*n FROM Nums WHERE n < (23456-12345+1)/15;

JOINSELECT,就像其中的一个,而不是series_tmp

除其他问题外,这将大大加速事态的发展。

问题2

你是GROUPing BY seriesORDERingtimestamp。它们是相关的,所以你可能会得到‘正确’的答案。但想想看。

问题3

你似乎在建造“水桶”(称为“系列”?)来自“时间戳”。这是正确的吗?如果是这样的话,让我们倒转--将“时间戳”转换为“桶”号:

代码语言:javascript
运行
复制
bucket_number = (timestamp - start) / bucket_size

通过在整个过程中这样做,您可以避免“问题1”,并消除我对它的解决方案。也就是说,根据桶来重新表示整个查询。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34657561

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档