【问题标题】:How to speed up this slow query如何加快这个慢查询
【发布时间】:2019-02-06 05:43:54
【问题描述】:

我设计了一个 mysql 数据库并加载了一些数据(可能总共 10 个 mio 行)。 我正在尝试从时间间隔重叠的两个表中获取数据。

SELECT 
        cd.ParameterID,
        intervals.TimeStamp,
        intervals.GreenHouseID,
        intervals.TargetParam,
        intervals.ProductionID
FROM
        (
                SELECT 
                        pd.TimeStamp, 
                        p.GreenHouseID, 
                        pd.ParameterID AS TargetParam, 
                        pd.ProductionID
                FROM 
                        Production p INNER JOIN 
                        ProductionData pd ON pd.ProductionID=p.ID
                GROUP BY
                        pd.TimeStamp, p.GreenHouseID
        ) AS intervals,
    ClimateData cd
WHERE
        DATE_FORMAT(intervals.TimeStamp,'%Y-%m-%d') = DATE_FORMAT(cd.Time_stamp,'%Y-%m-%d') AND
        cd.GreenHouseID = intervals.GreenHouseID
GROUP BY
        intervals.ProductionID, intervals.TargetParam

很遗憾,查询花费的时间太长(我还没有看到它完成)。

当我使用EXPLAIN 时,我得到以下结果:

|id|select_type|table     |partitions|type |possible_keys|key          |key_len|ref                   |rows|filtered|Extra
|1|PRIMARY     |<derived2>|NULL      |ALL  |NULL         |NULL         |NULL   |NULL                  | 416|  100.00|Using where Using temporary
|1|PRIMARY     |cd        |NULL      |ref  |cd_ghid_idx  |cd_ghid_idx  |4      |intervals.GreenHouseID|1660|  100.00|Using where       
|2|DERIVED     |p         |NULL      |index|PRIMARY      |pr_gh_fk_idx |5      |NULL                  |  13|  100.00|Using index Using temporary
|2|DERIVED     |pd        |NULL      |ref  |pd_pr_fk_idx |pd_pr_fk_idx |5      |ghdb.p.ID             |  32|  100.00|NULL 

我相信我在所有相关列上都放置了索引以确保快速查询。但是,我设计的查询使用临时表 (intervals)。这会降低性能吗?如果是这样,如何设计一个更快的查询?

mysql 服务器在我的笔记本电脑上(16GB RAM,CPU E3-1505M v5)。我没有对 mysql 设置进行任何更改。那会有用吗?

我希望在适当的时间内得到查询结果(几分钟就可以了)。

谢谢。

【问题讨论】:

  • 您的查询充满了问题。如果您不汇总任何内容,为什么要使用GROUP BY。我认为您应该包括示例输入数据和预期输出。也许只是正确地重写您的查询就可以解决性能问题。
  • 您是否尝试过跳过DATE_FORMAT 条件?这可能会减慢一切,因为对于每一行,时间戳都必须格式化
  • 为什么不加入生产 cd.GreenHouseID = interval.GreenHouseID
  • 并按 2 次分组使其更慢
  • 在 MySQL 中,函数不能使用索引,因此在性能方面加入 function( column) 绝不是一个好主意。

标签: mysql sql performance explain


【解决方案1】:
  • 请为每个表提供SHOW CREATE TABLE,包括临时表。
  • 临时表上似乎有一个单列索引?
  • 临时和永久在性能上应该没有区别。但是,创建临时表的额外步骤可能会造成损失。
  • 在适当的时候说NOT NULL
  • 在函数调用中隐藏列(在您的情况下为 DATE_FORMAT)会阻止使用索引 - 因此是 ALL
  • 您不能“调整自己的方式来解决性能问题”,所以我不会解决调整问题,只是询问innodb_buffer_pool_size 的值。
  • 请不要使用“逗号连接”;相反,使用JOIN .. ON ..

主要的性能问题在这里:

WHERE DATE_FORMAT(intervals.TimeStamp,'%Y-%m-%d') = 
      DATE_FORMAT(cd.Time_stamp,'%Y-%m-%d')
  AND cd.GreenHouseID = intervals.GreenHouseID

它需要看起来更像

WHERE intervals.TimeStamp ...
  AND cd.GreenHouseID = intervals.GreenHouseID

由于您要即时构建intervals,因此有一个仅包含日期的列。你也可以通过DATE(...)而不是DATE_FORMAT(...)来计算它。

由于您正在计算其中一个日期,请将pd.TimeStamp 更改为

    DATE(pd.TimeStamp) AS TS_Date

那么,

WHERE intervals.TimeStamp >= cd.TS_Date
  AND intervals.TimeStamp  < cd.TS_Date + INTERVAL 1 DAY
  AND intervals.GreenHouseID = cd.GreenHouseID

您还需要在intervals 上加上这个“复合”索引:

INDEX(GreenHouseID, TimeStamp) -- in this order

Bug 剩余:我看到了GROUP BY pd.TimeStamp, ...;这没有意义,所以我忽略它。

【讨论】:

    猜你喜欢
    • 2017-12-23
    • 2018-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 2013-04-19
    相关资源
    最近更新 更多