【发布时间】:2017-09-06 07:29:43
【问题描述】:
我有以下疑问:
DECLARE @application_number CHAR(8)= '37832904';
SELECT
la.LEASE_NUMBER AS lease_number,
la.[LEASE_APPLICATION] AS application_number,
tnu.[FOLLOWUP_CODE] AS note_type_code -- catch codes not in codes table
FROM [dbo].[lease_applications] la
LEFT JOIN [dbo].tickler_notes_uniq tnu ON tnu.[ACCOUNT_NUMBER] = la.[ACCOUNT_NUMBER]
WHERE la.LEASE_APPLICATION = @application_number
OR @application_number IS NULL;
SELECT
la.LEASE_NUMBER AS lease_number,
la.[LEASE_APPLICATION] AS application_number,
tnu.[FOLLOWUP_CODE] AS note_type_code -- catch codes not in codes table
FROM [dbo].[lease_applications] la
LEFT JOIN [dbo].tickler_notes_uniq tnu ON tnu.[ACCOUNT_NUMBER] = la.[ACCOUNT_NUMBER]
WHERE la.LEASE_APPLICATION = @application_number;
这两个查询之间的唯一区别是我添加了检查变量是否为 NULL。
您可以找到图形计划here
所以问题是。为什么计划如此不同?
更新:
第一个查询的实际执行计划可以找到here
OPTION(RECOMPILE) 将实际执行计划更改为好的计划。然而,这样做的缺点是我的主要目标是使用这些参数创建 TVF,然后使用该功能的每个人都应该提供该选项。
值得一提的是,我的主要目标是创建具有 2 个参数的 TVF。每一个都可能为空,也可能不是,但至少有一个应该是 NOT NULL。这些参数或多或少相等,它们只是两个表中的不同键,无论如何都会给出相同的结果(相同的行数等等)。这就是为什么我想做类似的事情
WHERE (col1 = @param1 OR @param1 IS NULL) AND (col2 = @param2 OR @param2 IS NULL) AND (@param1 IS NOT NULL or @param2 IS NOT NULL)
所以,基本上我对所有记录都不感兴趣
【问题讨论】:
-
因为第一个考虑到
@application_number是NULL的可能性,这意味着条件la.LEASE_APPLICATION = @application_number可能根本不会过滤任何行。第二个知道。 -
在这种情况下它不为空,但优化器必须生成一个对所有可能情况都有效的计划。尝试添加
WITH (RECOMPILE),这至少应该使估计值朝正确的方向倾斜(但可能不会改变实际计划)。OPTION (OPTIMIZE FOR (@application_number = '37832904'))是另一种可能性。同样,当缓存的计划被重用时,实际计划仍然必须考虑到运行时该值为 null 的可能性。OR @x IS NULL条件很麻烦,这就是为什么人们经常使用IF并拆分语句。 -
OPTION (RECOMPILE)不是WITH (RECOMPILE)。然后 SQL Server 将在每次调用时重新编译语句而不缓存计划 - 因此它可以针对特定值进行优化。但是你每次都要支付编译费用。 -
而且你不会在估计的计划中看到
OPTION (RECOMPILE)的效果。您将需要实际执行查询并获取实际计划。
标签: sql-server sql-server-2014 sql-execution-plan sqlperformance