【问题标题】:Scan where I would expect to see seek扫描我希望看到的地方
【发布时间】:2017-01-25 11:13:43
【问题描述】:

我有一个表 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)

但是我现在从执行计划中看到该表已被扫描

这是为什么?

【问题讨论】:

  • 你使用的是什么版本的sql

标签: sql sql-server indexing


【解决方案1】:

在您的第二个查询中,问题出在您的 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 将缓存参数化的执行计划。当您有超过 2 个可选参数时,这通常是一个更大的问题。

【讨论】:

    猜你喜欢
    • 2017-10-20
    • 1970-01-01
    • 2022-12-11
    • 2012-01-12
    • 1970-01-01
    • 2013-10-17
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多