0

我在 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

子查询包含UNIONShierarchy和 INNER JOINS。expenditure子查询基于多个级别的子查询,并包含 UNIONS、INNER 和 LEFT JOINS,并最终包含 PIVOT 聚合。

hierarchy子查询本身在 2 秒内运行并返回 467 行。expenditure子查询本身在 7 秒内运行并返回 458 行。如果没有该子句,ORDER BY查询将在 11 秒内运行。但是,使用ORDER BY子句,查询将在 11分钟内运行。

实际执行计划揭示了不同之处。如果没有该ORDER BY子句,则 thehierarchyexpenditure子查询都运行一次,结果将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 解决方案而创建一个存储过程。

关于此问题的原因或解决方法的任何想法?

4

2 回答 2

1

感谢@MartinSmith 的评论,我开始研究可能导致expenditureORDER BY版本中子查询提供的估计行和实际行之间的主要差异的原因,即使我最终想要这样做ORDER。我想,如果我可以稍微优化一下那个版本,也许这也会使这个ORDER BY版本受益。

正如我在 OP 中提到的,expenditure子查询包含PIVOT另一个子查询(我们称之为unaggregated_expenditure)的聚合。我在 thePIVOT和子查询之间添加了一个层,该层在跨所需的几个枢轴列unaggregated_expenditure之前聚合了所需的列。PIVOT这增加了一些概念上的复杂性,但能够将估计的行数PIVOT从 106,245,000 减少到 10,307。此更改在应用于ORDER BY整个查询的版本时,会产生不同的实际执行计划,该计划能够在所需的 11 秒内处理和交付查询。

于 2013-06-14T10:07:31.517 回答
1

为了避免嵌套循环连接,你可以给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)

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

于 2013-06-13T16:57:24.080 回答