我正在重写不再需要所有数据的查询。我的问题是,我从未见过、也没有在StackExchange上发现任何专门解决这个问题的实践。
我知道HAVING语句的目的是在聚合上引入条件,就像WHERE在单个行上引入条件一样。但是,我在这段代码中看到的是,在带有聚合的查询中使用HAVING代替WHERE。HAVING中的条件不是应用于聚合,而是应用于非聚合列。
例如:
SELECT id, filedate, SUM(amount)
FROM Sales
GROUP BY id, filedate
HAVING id = 123 AND filedate = '1/1/2018'相对于:
SELECT id, filedate, SUM(amount)
FROM Sales
WHERE id = 123 AND filedate = '1/1/2018'
GROUP BY id, filedate这种策略是否有性能方面的影响或其他优点/缺点?
我自己还没有试过运行诊断,而不是优先考虑,我必须自己去做。不过,如果没有一个明确的答案,我想我可能会的。
我关心的是优化器如何看待这个查询。它是聚合所有数据,然后根据HAVING子句限制结果集,还是实现了它可以对单个行应用有条件,因为它们专门引用非聚合列?
编辑:对于我的示例查询和我正在重写的实际SQL,这些计划是相同的,但是这些查询具有类似的复杂性,我还没有足够的知识从相同的计划中得出结论。
发布于 2018-01-24 19:52:56
HAVING中的条件不是应用于聚合,而是应用于非聚合列。
这里的问题在于您如何描述HAVING子句适用于什么。HAVING子句总是应用于聚合字段,这些字段是聚合后剩下的所有列。您正在试图显示/说明HAVING子句没有应用于任何聚合函数,这正是它们通常应用的内容。但实际上,HAVING子句控制聚合函数的结果,或者,在第一个示例中,控制分组列的结果。但在这两种情况下,已经执行了聚合。
因此,在性能方面(更不用说其他尝试稍后更新此代码的人的可读性),您可以使用WHERE子句过滤到将聚合的代码,然后使用HAVING子句过滤出已经聚合的代码。而且,虽然问题中所示的简单测试的结果掩盖了这两个(或在处理查询的序列中的逻辑位置)之间的时间差异,以至于它们“似乎”在做相同的事情,但如果聚集一组行的效率不降低,但在逻辑上它们在存储/计算聚合之前就可以被删除时,我会感到非常惊讶。但是,如果您确实看到它们的执行计划对于这个简单的示例是相似的,那么我敢打赌,这仅仅是因为优化器看到在执行查询之前重写查询时使这些HAVING条件成为实际的WHERE条件会更有效。但在这种情况下,我仍然建议不要以这种方式编写查询,因为当优化器应该花费时间/ CPU周期寻找更有效的计划时,您会让优化器需要额外的时间来重写糟糕的代码。@DavidSpillett补充道(在对这个答案的评论中):“此外,您还依赖于查询规划师看到优化潜力,这在更复杂的查询中可能不是这样,或者如果您的代码最终移植到另一个数据库(甚至只是一个较旧版本的Server)。”
就其价值而言,即使是微软现有子句的文档也表示,在没有GROUP BY存在的情况下,它充当了WHERE子句。既然文档已经在GitHub上了,我最近就可以通过拉动请求#235:纠正和改进“拥有”子句更正它了。
发布于 2018-01-24 20:18:36
所罗门给出了很好的解释,但对我来说,简单的答案是记住SQL查询逻辑处理顺序,就像Itzik Ben-Gan写的这里序列总是。
从-> ->组通过->让->选择-> ORDER
所以您可以看到,如果我们可以在分组之前应用WHERE过滤器,我们可以减少按组处理的数据量,特别是当适当的索引存在时,操作会非常有效。因此,如果使用WHERE并从业务角度返回相同的结果,则WHERE总是胜利者。
https://dba.stackexchange.com/questions/196158
复制相似问题