数据库
首页 > 数据库> > 优化无法解释的缓慢MySQL查询

优化无法解释的缓慢MySQL查询

作者:互联网

我在一个愚蠢的查询上掉头发了.首先,我将解释其目标.我每小时获取一组值并将其存储在数据库中.这些值可以随时间增加或保持相等.此查询每天提取最近60天的最新值(我有双胞胎查询按几周和几个月提取最新值,它们相似).该查询是不言自明的:

SELECT l.value AS value
FROM atable AS l
WHERE l.time = (
                  SELECT MAX(m.time)
                  FROM atable AS m
                  WHERE DATE(l.time) = DATE(m.time) 
                  LIMIT 1
               )
ORDER BY l.time DESC 
LIMIT 60

看起来没什么特别的.但考虑到时间是一个索引并且表包含的行数少于5000,它的运行速度极其缓慢(大于30秒).而且我敢肯定问题出在子查询上.

新手错误在哪里?

更新1:同样的情况,如果我避免使用SELECT m.time … ORDER BY m.time DESC.

更新2:似乎已多次调用DATE()函数不是问题.我试图创建一个计算的现场日期DATE. UPDATE可用SET天= DATE(时间)的运行时间少于2秒.修改后的查询具有l.day = m.day(无功能!),其运行时间与之前完全相同.

解决方法:

我看到的主要问题是在WHERE子句的表达式左侧使用了DATE().在WHERE表达式的两侧使用函数DATE()显式阻止MySQL在日期字段上使用索引.相反,它必须扫描所有行以将功能应用于每行.

代替这个:

WHERE DATE(l.time) = DATE(m.time) 

尝试这样的事情:

WHERE l.time BETWEEN
  DATE_SUB(m.date, INTERVAL TIME_TO_SEC(m.date) SECOND)
  AND DATE_ADD(DATE_SUB(m.date, INTERVAL TIME_TO_SEC(m.date) SECOND), INTERVAL 86399 SECOND)

也许您知道比上述示例有更好的方法将m.date转换为2012-02-09 00:00:00和2012-02-09 23:59:59之类的范围,但是您的想法是在这种情况下,将表达式的左侧保留为原始列名l.time,并在右侧以两个常量(或两个可以转换为常量的表达式)的形式为其指定范围.

编辑

我正在使用您的预先计算的天数字段:

SELECT *
FROM atable a
WHERE a.time IN
(SELECT MAX(time)
FROM atable
GROUP BY day
ORDER BY day DESC
LIMIT 60)

至少在这里,内部查询仅运行一次,然后使用IN簇进行二进制搜索.您仍在扫描表,但是只扫描一次,而内部查询只运行一次的优势可能会造成巨大的损失.

如果您知道每天都有值,则可以通过添加WHERE子句,将其限制为最近60个日历日并丢失LIMIT 60来改进内部查询.请确保已为日期和时间建立索引.

标签:aggregate-functions,subquery,query-optimization,mysql
来源: https://codeday.me/bug/20191101/1985632.html