我有一个表Table,在SQL Server数据库中有两列PKColumn1和Column2。该表具有聚集索引,聚集索引在PKColumn1上。
如果我对该表使用以下查询,则我希望执行计划显示聚簇索引查找。
SELECT PKColumn1
FROM Table
WHERE PKColumn1 = 1
它应做的。
如果我对该表使用以下查询,则我也希望执行计划显示聚簇索引查找。
DECLARE @PKColumn1 INT = 1;
SELECT PKColumn1
FROM Table
WHERE (PKColumn1 = @PKColumn1 OR @PKColumn1 IS NULL)
但是我现在从执行计划中看到该表已被扫描。
为什么是这样?
最佳答案
在第二个查询中,问题出在where子句中:WHERE (PKColumn1 = @PKColumn1 OR @PKColumn1 IS NULL)
。
SQL Server不会发生任何短路(例如在C#||中),这意味着即使表达式@PKColumn1 IS NULL
的计算结果为true,也无法保证sql server将不会计算第二个表达式PKColumn1 = @PKColumn1
。
解决方案:
处理此类可选参数的最佳方法是使用动态SQL并动态构建查询。就像是....
DECLARE @PKColumn1 INT = 1
,@Sql NVARCHAR(MAX);
SET @Sql = N' SELECT PKColumn1
FROM Table
WHERE 1 = 1 '
+ CASE WHEN @PKColumn1 IS NOT NULL THEN
N' AND PKColumn1 = @PKColumn1 ' ELSE N'' END
Exec sp_executesql @Sql
,N'@PKColumn1 INT'
,@PKColumn1
使用sp_executesql将缓存参数化的执行计划。当您有两个以上的可选参数时,这通常是一个问题。