我有一个表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将缓存参数化的执行计划。当您有两个以上的可选参数时,这通常是一个问题。

08-24 17:45