【发布时间】:2011-02-02 16:19:23
【问题描述】:
我注意到 SQL Server(在本例中为 SQL Server 2008)如何处理 select 语句中的相关子查询有些出人意料。我的假设是,查询计划不应该仅仅受到 select 语句的投影子句中写入子查询(或列)的顺序的影响。但是,情况似乎并非如此。
考虑以下两个查询,除了 CTE 中子查询的顺序之外,它们是相同的:
--query 1: subquery for Color is second
WITH vw AS
(
SELECT p.[ID],
(SELECT TOP(1) [FirstName] FROM [Preference] WHERE p.ID = ID AND [FirstName] IS NOT NULL ORDER BY [LastModified] DESC) [FirstName],
(SELECT TOP(1) [Color] FROM [Preference] WHERE p.ID = ID AND [Color] IS NOT NULL ORDER BY [LastModified] DESC) [Color]
FROM Person p
)
SELECT ID, Color, FirstName
FROM vw
WHERE Color = 'Gray';
--query 2: subquery for Color is first
WITH vw AS
(
SELECT p.[ID],
(SELECT TOP(1) [Color] FROM [Preference] WHERE p.ID = ID AND [Color] IS NOT NULL ORDER BY [LastModified] DESC) [Color],
(SELECT TOP(1) [FirstName] FROM [Preference] WHERE p.ID = ID AND [FirstName] IS NOT NULL ORDER BY [LastModified] DESC) [FirstName]
FROM Person p
)
SELECT ID, Color, FirstName
FROM vw
WHERE Color = 'Gray';
如果您查看这两个查询计划,您会发现每个子查询都使用了一个外连接,并且连接的顺序与编写子查询的顺序相同。有一个过滤器应用于颜色的外部连接的结果,以过滤掉颜色不是“灰色”的行。 (我很奇怪 SQL 会为颜色子查询使用外连接,因为我对颜色子查询的结果有一个非空约束,但是可以。)
大部分行都被滤色器删除了。结果是查询 2 比查询 1 便宜得多,因为第二个连接涉及的行更少。除了构建这样一个语句的所有原因之外,这是预期的行为吗? SQL server 不应该选择在查询计划中尽早移动过滤器,而不管子查询的编写顺序如何?
编辑: 澄清一下,我正在探索这种情况是有正当理由的。我可能需要创建一个包含类似构造的子查询的视图,现在很明显,任何基于从视图投影的这些列的过滤都会因为列的顺序而在性能上有所不同!
【问题讨论】:
-
你为什么要使用相关子查询?为什么不使用连接呢?
-
如果您对每个子查询使用两个 CTE 表而不是一个,查询计划会是什么样子。
-
@HLGEM 我通常会使用连接,但在此示例中,我只对另一个表中的前 1(或 0)值感兴趣,其中可能有很多。
-
@Thomas 我认为我不能将 CTE 用于子查询,因为它们是相关的子查询。我无法对 CTE 进行参数化(尽管如果可以的话,那将非常简洁),所以我会有效地遇到我在下面 gbn 的查询中指出的同样问题。
标签: sql sql-server performance tsql subquery