【发布时间】:2013-06-13 16:30:54
【问题描述】:
我在 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 解决方案而创建存储过程。
关于此问题的原因或解决方法的任何想法?
【问题讨论】:
-
有多少估计的和实际的行进入嵌套循环?统计数据是最新的吗?
-
对一堆“联合和内连接”的输出进行排序无法与将输出作为一个整体排序到#temp 表中进行比较。基础表上是否有支持排序依据的索引?他们是工会还是工会所有人? TOP (2147483647) 到底在为你做什么?使您能够做一些糟糕的事情,例如将此查询放入带有 order by 子句的视图定义中?
-
@MartinSmith:好主意。
expenditures子查询中的子查询中的 1 个相关索引没有更新的统计信息。更新后,遗憾的是没有任何改善。从更新的实际执行计划来看:在非ORDER BY版本中,hierarchy子查询估计有 343 行(实际 467 行),expenditure子查询估计有 106,245,000 行(实际 459 行)。在ORDER BY版本中,hierarchy子查询估计有 343 行(实际 467 行),expenditure子查询估计有 104,648 行(实际 459 行)。 -
@AaronBertrand:涉及#temp_table 的测试是为了验证 SQL Server 实际上能够在合理的时间内产生我想要的结果。我知道比较两者的机制是没有用的。
hierarchy子查询有 3 个UNION ALL,expenditure子查询有很多很多UNION ALL和一些UNION在必要时。基础表包含支持ORDER BY子句的索引。您对 TOP (2147483647) 的看法是正确的;我这样做是有原因的,不会在此查询之上构建或运行任何视图或查询。有什么改进的想法吗?
标签: sql-server sql-order-by query-performance sql-execution-plan