【发布时间】:2012-05-03 16:16:49
【问题描述】:
我今天开的会议太多了,但我认为我的大脑软件还在。 在努力提高某些查询的性能时,我遇到了以下谜团(表名和字段的释义):
SELECT X.ADId FROM
(
SELECT DISTINCT A.ADId
FROM P WITH (NOLOCK)
INNER JOIN A WITH (NOLOCK) ON (P.ID = A.PId)
INNER JOIN dbo.fn_A(16) AS VD ON (VD.DId = A.ADId)
LEFT JOIN DPR ON (LDID = A.ADId)
WHERE ((A.ADId = 1) OR ((HDId IS NOT NULL) AND (HDId = 1))) AND
(P.PS NOT IN(5,7)) AND (A.ASP IN (2, 3))
) X
WHERE (dbo.fn_B(X.ADId, 16) = 1)
正如您将看到的,内部查询的内容大多是无关紧要的。 最初的重点是我想避免在每条记录上调用 fn_B(),因为它们包含 ADId 的重复值,所以我在内部做了一个 SELECT DISTINCT 然后过滤不同的记录。 听起来很合理吧?
谜团从这里开始……
内部查询返回 NO RECORDS(对于指定的参数)。 如果我注释掉“WHERE fn_B() = 1”,那么查询会在零时间内运行(并且不返回任何结果)。 如果我把它放回去,那么查询需要 6-10 秒,再次没有返回任何结果。
这似乎超过了常识,或者至少是我的常见 SQL 意识 :-) 如果内部查询没有返回数据,那么外部条件永远不应该被评估吗?
当然,我花时间检查了实际的执行计划,保存并非常仔细地比较了它们。它们 99% 相同,没有什么不寻常的地方,或者我认为是这样。
我玩弄了一些 CTE 以在第一个 CTE 中获取查询结果,然后将其传递给第二个 CTE,该 CTE 有一些保证不过滤任何记录的条件,然后在所有 CTE 之外评估 fn_B() 调用,但是行为完全相同。
还有其他变体,例如使用旧查询(可能以相同的值多次调用 fn_B())具有相同的行为。如果我删除条件,那么我在零时间内没有任何记录。如果我把它放回去,那么 10 秒内没有记录。
有什么想法吗?
感谢您的宝贵时间 :-)
PS1:我尝试使用一个简单的查询重现 tempdb 上的情况,但我无法实现。它只发生在我的实际桌子上。 PS2:这个查询是在另一个函数中调用的,所以将结果放在一个临时表中,然后进一步过滤它们也是不可能的。
【问题讨论】:
标签: sql-server-2008 database-performance