SQL Server查询 - ORDER BY在小结果集上查询查询性能

时间:2013-06-13 16:30:54

标签: sql-server sql-order-by query-performance sql-execution-plan

我在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子句,hierarchyexpenditure子查询都会运行一次,结果为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解决方案。

有关此问题的原因或修复的任何想法?

2 个答案:

答案 0 :(得分:1)

感谢@ MartinSmith的评论,我看到了什么可能导致非expenditure版本中ORDER BY子查询所提供的估计行和实际行之间的主要差异,即使我最终想要到ORDER它。我想也许如果我可以稍微优化那个版本,也许这也会使ORDER BY版本受益。

正如我在OP中提到的,expenditure子查询在另一个子查询中包含PIVOT聚合(让我们称之为unaggregated_expenditure)。我在PIVOTunaggregated_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)

我通常更喜欢让优化器找出正确的查询计划。然而,在极少数情况下,我遇到了类似于你的问题,需要提出建议,将其推向正确的方向