Sql 扫描我希望看到的地方

Sql 扫描我希望看到的地方,sql,sql-server,indexing,Sql,Sql Server,Indexing,我有一个表,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

我有一个表,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)
它确实做到了

如果对该表使用以下查询,我还希望执行计划显示聚集索引Seek

SELECT PKColumn1
FROM Table
WHERE PKColumn1 = 1
DECLARE @PKColumn1 INT = 1;
SELECT PKColumn1
FROM Table
WHERE (PKColumn1 = @PKColumn1 OR @PKColumn1 IS NULL)
但是,我现在从执行计划中看到,该表已被扫描


这是为什么?

在第二个查询中,问题在于where子句:

其中(PKColumn1=@PKColumn1或@PKColumn1为空)

SQL Server不执行任何短路(如在c#| | |),这意味着即使表达式
@PKColumn1为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将缓存参数化的执行计划。当您有两个以上的可选参数时,这通常是一个更大的问题

您正在使用哪个版本的sql