我在SQL Server 2008 R2中有一个查询,格式如下:
SELECT TOP (2147483647) *
FROM (
SELECT *
FROM sub_query_a
) hierarchy
LEFT JOIN (
SELECT *
FROM sub_query_b
) expenditure
ON hierarchy.x = expenditure.x AND hierarchy.y = expenditure.y
ORDER BY hierarchy.c, hierarchy.d, hierarchy.e
hierarchy
子查询包含UNIONS和INNER JOINS。 expenditure
子查询基于多个子子查询级别,包含UNIONS,INNER和LEFT JOINS,最终包含PIVOT聚合。
hierarchy
子查询本身在2秒内运行并返回467行。 expenditure
子查询本身在7秒内运行并返回458行。在没有 ORDER BY
子句的情况下,查询将在11秒内运行。但是, ORDER BY
子句,查询将在11 分钟中运行。
实际执行计划揭示了不同之处。如果没有ORDER BY
子句,hierarchy
和expenditure
子查询都会运行一次,结果为Merge Join (Right Outer Join)
。当包含ORDER BY
子句时,hierarchy
查询仍会运行一次,但expenditure
部分在层次结构查询中每行运行一次,并且结果Nested Loops (Left Outer Join)
连在一起。就好像ORDER BY
子句导致expenditure
子查询成为相关子查询(它不是)。
为了验证SQL Server实际上是否能够在11秒内执行查询并生成排序结果集,作为测试,我创建了一个临时表并插入了查询的结果,而不是 ORDER BY
条款进入它。然后我做了SELECT * FROM #temp_table ORDER BY c, d, e
。整个脚本花了预期的11秒,并返回了预期的结果。
我希望使用ORDER BY
子句作为一个查询有效地使查询工作 - 我不想创建存储过程只是为了启用#temp_table hacky解决方案。
有关此问题的原因或修复的任何想法?
答案 0 :(得分:1)
感谢@ MartinSmith的评论,我看到了什么可能导致非expenditure
版本中ORDER BY
子查询所提供的估计行和实际行之间的主要差异,即使我最终想要到ORDER
它。我想也许如果我可以稍微优化那个版本,也许这也会使ORDER BY
版本受益。
正如我在OP中提到的,expenditure
子查询在另一个子查询中包含PIVOT
聚合(让我们称之为unaggregated_expenditure
)。我在PIVOT
和unaggregated_expenditure
子查询之间添加了一个图层,该图层聚合了所需的列,然后PIVOT
在所需的几个数据透视列上显示相同的列。这增加了一些概念上的复杂性,但却能够将PIVOT
的估计行数从106,245,000减少到10,307。此更改在应用于整个查询的ORDER BY
版本时,会产生一个不同的实际执行计划,该计划能够在所需的11秒内处理和传递查询。
答案 1 :(得分:0)
为避免嵌套循环连接,您可以为编译器提供option
:
SELECT TOP (2147483647) *
FROM (
SELECT *
FROM sub_query_a
) hierarchy
LEFT JOIN (
SELECT *
FROM sub_query_b
) expenditure
ON hierarchy.x = expenditure.x AND hierarchy.y = expenditure.y
ORDER BY hierarchy.c, hierarchy.d, hierarchy.e
option (merge join, hash join)
我通常更喜欢让优化器找出正确的查询计划。然而,在极少数情况下,我遇到了类似于你的问题,需要提出建议,将其推向正确的方向