我今天开的会议太多了,但我想我的脑部软件还在。在我努力提高某些查询的性能时,我遇到了以下谜团(表名和字段释义):
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:这个查询是在另一个函数中调用的,所以将结果放在一个临时表中,然后进一步过滤它们也是不可能的。