使用变量时SQL Server执行计划的结果不一致

时间:2014-06-26 03:38:43

标签: sql-server

我有一张包含500万条记录的表格如下

Id          BasePrefix  DestPrefix  ExchangeSetId   ClassId
11643987    0257016         57016           1           3
11643988    0257016         57278           1           3
11643989    0257016         57279           1           3
11643990    0257016         57751           1           3

SQL Tuning顾问推荐以下索引

CREATE NONCLUSTERED INDEX [ExchangeIdx] ON [dbo].[Exchanges]
(
    [ExchangeSetId] ASC,
    [BasePrefix] ASC,
    [DestPrefix] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

但是考虑到以下

DECLARE @exchangeSetID int = 1;
DECLARE @BasePrefix nvarchar( 10 ) = '0732056456';
DECLARE @DestPrefix nvarchar( 10 ) = '30336456';
DECLARE @BaseLeft nvarchar( 10 ) = left(@BasePrefix,4);

这两个查询为我提供了截然不同的执行计划

查询1

SELECT TOP 1 ClassId
  FROM Exchanges
  WHERE
  exchangeSetID = @exchangeSetID
   AND BasePrefix LIKE '0732' + '%'
   AND '0732056456' LIKE BasePrefix + '%'
   AND '30336456' LIKE DestPrefix + '%';

enter image description here

<小时/> 查询2

SELECT TOP 1 ClassId
  FROM Exchanges
  WHERE
  exchangeSetID = @exchangeSetID
   AND BasePrefix LIKE @BaseLeft + '%'
   AND @BasePrefix LIKE BasePrefix + '%'
   AND @DestPrefix LIKE DestPrefix + '%';

enter image description here


两个查询之间的差异分别为@BaseLeft'0732'

基本上,在第一个例子中使用了索引,而在第二个例子中,没有那么多

有没有令人信服的理由说明为什么会这样?

如果这不仅仅是我思考的一个根本缺陷,我怎样才能将变量传递给第二个查询并使用索引?

1 个答案:

答案 0 :(得分:1)

此行为的解释是引爆点(#1#2)。

基本上,根据谓词的选择性,它影响从缓冲池中读取多少8K数据页,SQL Server有两个选项来过滤行:

1)索引搜索+键/ RID查找

2)表/ [Clustere]指数扫描。

为什么SQL Server可以使用Scan而不是Seek + Lookup?因为,在某些情况下(低/中/中高选择性),使用Seek + Lookup可以从缓冲池中读取比单个扫描更多的页面。

怎么办?你应该创建一个覆盖索引:

create nonclustered index ...
on ... (...)
include (ClassId);