繁体   English   中英

SQL:重用函数结果而不使用子查询的查询

[英]SQL: Reuse function result in query without using sub-query

在存储销售订单的MySQL数据库表中,我有一个LastReviewed列,其中保存了修改销售订单的最后日期和时间(类型timestamp ,默认值CURRENT_TIMESTAMP )。 我想绘制特定用户在过去90天内每天修改的销售数量。

我正在尝试制作一个SELECT ,该SELECT返回自LastReviewed日期以来的天数,以及该范围内有多少条记录。 以下是我的查询,效果很好:

SELECT DATEDIFF(CURDATE(), LastReviewed) AS days, COUNT(*) AS number FROM sales
WHERE UserID=123 AND DATEDIFF(CURDATE(),LastReviewed)<=90
GROUP BY days
ORDER BY days ASC

请注意,我为每条记录多次计算DATEDIFF()CURDATE() 这似乎确实无效,所以我想知道如何重用之前的计算结果。 我尝试的第一件事是:

SELECT DATEDIFF(CURDATE(), LastReviewed) AS days, COUNT(*) AS number FROM sales
WHERE UserID=123 AND days<=90
GROUP BY days
ORDER BY days ASC

错误: Unknown column 'days' in 'where clause' 于是我开始环顾四周。 基于另一个讨论( 我可以在SELECT查询中重用计算字段吗? ),接下来我尝试了以下方法:

SELECT DATEDIFF(CURDATE(), LastReviewed) AS days, COUNT(*) AS number FROM sales
WHERE UserID=123 AND (SELECT days)<=90
GROUP BY days
ORDER BY days ASC

错误: Unknown column 'days' in 'field list' 我也尝试了以下方法:

SELECT @days := DATEDIFF(CURDATE(), LastReviewed) AS days, 
       COUNT(*) AS number FROM sales
WHERE UserID=123 AND @days <=90
GROUP BY days
ORDER BY days ASC

该查询返回零结果,因此,即使我将其放入SELECT子句并删除WHERE子句, @days<=90似乎仍返回false ,我可以看到@days值低于90的一些结果。

我已经通过使用子查询来使事情工作:

SELECT * FROM (
  SELECT DATEDIFF(CURDATE(),LastReviewed) AS sales , 
         COUNT(*) AS number FROM sales
  WHERE UserID=123
  GROUP BY days
) AS t
WHERE days<=90
ORDER BY days ASC

但是我不知道这是否是最有效的方法。 更不用说即使此解决方案为每条记录计算一次CURDATE() ,即使其值从查询开始到结束都相同。 那不是浪费吗? 我在想这个吗? 欢迎提供帮助。

注意:Mod,这应该在CodeReview上吗? 我在这里发布的原因是我尝试使用的代码实际上无法正常工作

您的问题实际上有两个问题。

首先,您忽略了WHERESELECT之前的事实。 当服务器评估WHERE <expression> ,它便已经知道为评估<expression>所做的计算的值,并且可以将这些值用于SELECT

但是,更糟糕的是,您几乎绝不应该编写将列用作函数参数的查询,因为这通常需要服务器为每一行评估表达式。

相反,您应该使用以下代码:

WHERE LastReviewed < DATE_SUB(CURDATE(), INTERVAL 90 DAY)

优化器将看到这一点并为之兴奋,因为DATE_SUB(CURDATE(), INTERVAL 90 DAY)可以解析为一个常量,可以在<比较的一侧使用,这意味着如果存在LastReviewed为最左侧的相关列,则服务器可以使用索引立即消除LastReviewed >=该常数值的所有行。

然后DATEDIFF(CURDATE(), LastReviewed) AS days将仅针对我们已经知道想要的行来评估DATEDIFF(CURDATE(), LastReviewed) AS days (仍然需要SELECT )。

在(UserID,LastReviewed)上添加单个索引,服务器将能够非常快速地精确定位相关行。

内置函数比获取行要便宜得多。

使用下面的“ composite”索引,您可以获得更多的性能改进:

INDEX(UserID, LastReviewed)

更改为

WHERE UserID=123
  AND LastReviewed >= CURRENT_DATE() - INTERVAL 90 DAY

您的公式在函数调用中“隐藏” LastRevieded ,使其在索引中不可用。

如果您仍然对该改进不满意,请考虑每晚查询一次,该查询计算昨天的统计信息并将其放在“汇总表”中。 从那里,您提到的SELECT可以运行得更快。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM