【发布时间】:2018-06-18 23:01:01
【问题描述】:
假设一个简单的表定义为:
CREATE TABLE Table1
(
[ID] [bigint] NOT NULL IDENTITY(1, 1) NOT FOR REPLICATION,
[State] [tinyint] NOT NULL DEFAULT ((0))
)
ALTER TABLE Table1 ADD CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED ([ID])
CREATE NONCLUSTERED INDEX [IX_NC_F_Media_StateNotDeleted] ON Table1 ([State]) WHERE ([State]<>(2))
CREATE NONCLUSTERED INDEX [IX_NC_F_Media_State] ON Table1 ([State]) WHERE ([State]=(0))
值插入如下:
250000 rows with State = 0
1000 rows with State = 5
以及以下查询及其各自的执行计划:
declare @mID int = 400000;
select State
from Table1
where (ID = @mID and State in (0, 1, 4, 5))
or (@mID IS NULL and State in (0, 4))
考虑到ID 不为空,因此@mid IS NULL 与ID = @mID 互斥,我将查询重写为:
declare @mID int = 400000;
if @mID is null
begin
select State
from Table1
where State in (0, 4)
end
else
begin
select State
from Table1
where ID=@mID and State in (0, 1, 4, 5)
end
问题:
- 为什么这两种情况的执行计划不同?为什么非聚集索引只用于第二种情况?
- 尽管当
@mID为空时,第二种情况会执行查找和扫描,但它真的有什么区别吗?工具提示表明性能影响几乎相同,我猜这是因为数据主要是State = 0行。
【问题讨论】:
-
执行计划之间存在差异,因为第一个查询比第二个查询具有更多过滤条件(在 if else 块内)。 SQL 必须创建执行计划,该计划应该在您下次执行相同的查询时起作用(可能是下次您将在参数中传递 NULL)。
-
如果你执行以上两种情况(第一种@mID不为空,第二种@mID为空),那么你会在SQL缓存中找到三个执行计划(三个执行计划
selects您的案例)。 -
@BhatiaAshish:我知道由于 if 语句在第二种情况下存在差异,但我想知道为什么非聚集索引仅在第二种情况下被激活而不是在第一个。
-
SQL Server 仅对此查询使用非聚集索引 -
select State from Table1 where State in (0, 4),因为只有一个 NC 索引包含 (0,4) 中的状态数据。
标签: sql sql-server tsql