为什么有的执行计划中没有“Seek谓词”(都属于索引查找)?

时间:2021-10-16 20:53:54
为什么有的执行计划中没有“Seek谓词”(都属于索引查找)?

这个有”Seek谓词字样“:
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 0

这样就没有”Seek谓词字样“:
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 1
AND FromHour <= DATEPART(HH, GETDATE()) AND DATEPART(HH, GETDATE()) <= ToHour

如果没有 Seek 谓词 字样,索引查找用上了吗?

15 个解决方案

#1


另外问一下,由于必须用到 AND 和 OR 的组合,导致索引查询失效,我可以用 UNION  ALL 分开写成2次查询,问题是:
用 UNION  AL 分开2次查询速度快,还是舍弃部分索引速度快(我用的复合索引,至少前3个是可以用上的)?

#2


如果没有 Seek 谓词 字样,索引查找用上了吗?
----
没有用上,是否需要用要看执行成本,表太小或查询结果集占用50%以上的数据时,数据库会用表扫描
是不是显示 Table Scan--这开销成本是比较大的

这两列是不是没有建索引,没有时建上
FromHour
ToHour

#3


看执行计划时要留意有没有并行,有并行的情况性能是更优的

#4


引用 2 楼 roy_88 的回复:
如果没有 Seek 谓词 字样,索引查找用上了吗?
----
没有用上,是否需要用要看执行成本,表太小或查询结果集占用50%以上的数据时,数据库会用表扫描
是不是显示 Table Scan--这开销成本是比较大的

这两列是不是没有建索引,没有时建上
FromHour
ToHour


我是建的复合索引:
b, c, d, h, m, LimitRange, FromHour, ToHour

顺序也没有问题,是不是 FromHour <= xxx 无法用索引?

另外,如何看有没有并行?执行计划中的箭头分叉就是并行吗?

#5


引用 4 楼 oldhunter 的回复:
Quote: 引用 2 楼 roy_88 的回复:

如果没有 Seek 谓词 字样,索引查找用上了吗?
----
没有用上,是否需要用要看执行成本,表太小或查询结果集占用50%以上的数据时,数据库会用表扫描
是不是显示 Table Scan--这开销成本是比较大的

这两列是不是没有建索引,没有时建上
FromHour
ToHour


我是建的复合索引:
b, c, d, h, m, LimitRange, FromHour, ToHour

顺序也没有问题,是不是 FromHour <= xxx 无法用索引?

另外,如何看有没有并行?执行计划中的箭头分叉就是并行吗?


你最好贴出执行步骤或执行计划图?看你的语句是不会出现你所说的情况

会出现,那是你查询条件大概占用表数>=50%左右或<0.8%左右时会用到表扫描,具体占用比例各版本可能有所区别

#6



确实,这次有谓词了,不过为什么FromHour索引没有用上?

--这个有“Seek谓词”
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 0
 
--现在都有“Seek谓词”,但为什么FromHour索引没有用上?
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 1
AND FromHour <= DATEPART(HH, GETDATE()) AND DATEPART(HH, GETDATE()) <= ToHour


#7


引用 6 楼 oldhunter 的回复:
确实,这次有谓词了,不过为什么FromHour索引没有用上?

--这个有“Seek谓词”
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 0
 
--现在都有“Seek谓词”,但为什么FromHour索引没有用上?
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 1
AND FromHour <= DATEPART(HH, GETDATE()) AND DATEPART(HH, GETDATE()) <= ToHour

按你贴出来的语句会用上,你能贴出你的执行计划不?这样的问题没法猜
特定情况下开销成本大时不会用上或索引与条件不合理时会用不上

#8


下面分别是执行计划、索引列,以及建表的SQL。您看一下,为什么FromHour没有用上索引?

为什么有的执行计划中没有“Seek谓词”(都属于索引查找)?
为什么有的执行计划中没有“Seek谓词”(都属于索引查找)?

CREATE TABLE [dbo].[t](
[id] [int] IDENTITY(1,1) NOT NULL,
[a] [int] NOT NULL,
[b] [bit] NOT NULL,
[c] [tinyint] NOT NULL,
[d] [int] NOT NULL,
[h] [int] NOT NULL,
[m] [int] NOT NULL,
[LimitRange] [bit] NOT NULL,
[FromHour] [int] NOT NULL,
[ToHour] [int] NOT NULL,
[LastTime] [datetime] NULL,
 CONSTRAINT [PK_t] PRIMARY KEY CLUSTERED 
(
[id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleEnabled]  DEFAULT ((0)) FOR [b]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleMode]  DEFAULT ((0)) FOR [c]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleDays]  DEFAULT ((0)) FOR [d]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleHours]  DEFAULT ((0)) FOR [h]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleMinutes]  DEFAULT ((0)) FOR [m]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleLimitTimeRange]  DEFAULT ((0)) FOR [LimitRange]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleFromHour]  DEFAULT ((0)) FOR [FromHour]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleToHour]  DEFAULT ((23)) FOR [ToHour]
GO


declare @count int = 1;
while @count < 1000
begin
insert into t (a, b, c, LimitRange)
values (1, 1, 1, 1)
set @count = @count + 1
end

#9


引用 7楼中国风 的回复:
Quote: 引用 6 楼 oldhunter 的回复:


确实,这次有谓词了,不过为什么FromHour索引没有用上?

--这个有“Seek谓词”
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 0
 
--现在都有“Seek谓词”,但为什么FromHour索引没有用上?
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 1
AND FromHour <= DATEPART(HH, GETDATE()) AND DATEPART(HH, GETDATE()) <= ToHour

按你贴出来的语句会用上,你能贴出你的执行计划不?这样的问题没法猜
特定情况下开销成本大时不会用上或索引与条件不合理时会用不上
up

#10


执行计划属于,有序聚集索引+非聚集索引查找
执行计划没问题,有用到索引,最后条件是固定值 和范围值要计算开始位置是分开的,执行计划是 index seek 不可能是index Scan(这是范围查找)

如果没有用到索引会显示,条件执行计划会显示在聚集索引分支上


#11


引用 10楼中国风 的回复:
执行计划属于,有序聚集索引+非聚集索引查找
执行计划没问题,有用到索引,最后条件是固定值 和范围值要计算开始位置是分开的,执行计划是 index seek 不可能是index Scan(这是范围查找)

如果没有用到索引会显示,条件执行计划会显示在聚集索引分支上
seek谓词中没有出现 FromHour,是不是表示 FromHour 没有参与 index seek?

#12


引用 11楼我是你的主体 的回复:
Quote: 引用 10楼中国风 的回复:
执行计划属于,有序聚集索引+非聚集索引查找
执行计划没问题,有用到索引,最后条件是固定值 和范围值要计算开始位置是分开的,执行计划是 index seek 不可能是index Scan(这是范围查找)

如果没有用到索引会显示,条件执行计划会显示在聚集索引分支上
seek谓词中没有出现 FromHour,是不是表示 FromHour 没有参与 index seek?
up

#13


引用 11 楼 oldhunter 的回复:
Quote: 引用 10楼中国风 的回复:
执行计划属于,有序聚集索引+非聚集索引查找
执行计划没问题,有用到索引,最后条件是固定值 和范围值要计算开始位置是分开的,执行计划是 index seek 不可能是index Scan(这是范围查找)

如果没有用到索引会显示,条件执行计划会显示在聚集索引分支上
seek谓词中没有出现 FromHour,是不是表示 FromHour 没有参与 index seek?


没用到非聚集索引时,会用聚集索引查找或扫描或堆扫描(开销会大,执行计划占用成本会有显示)

#14


我来说个观察后的推测结论。大家认为不对可以指出。
你的图片里(截图都不截全,太小家子气了。开玩笑哈)。你的执行计划有索引查找,但还有“键查找”,出现这个“键查找”说明,你虽然用到了索引,但该索引没有覆盖(include)好的你的select字段。当你的查找结果占整表占比比较小时,这个速度还是比scan快。但是,如果占比比较大时,(版主说的50%都算是客气的),估计20%(我也是随便估的)就算大了。这时,索引查找+键查找的速度估计还没有聚集索引扫描快(即不用索引而全表扫描)。当然,如果这种情况,优化器大多时会自动把执行计划变成"聚集索引扫描"。但你的执行计划没变说明,你的结果集没有到这种程度,或者,优化器没有通过统计信息得出正确的执行预算。那么,你还要“频繁”使用上面的语句的话,你把所有select的字段,都放进include里,创建覆盖索引,就不会出现键查找了,查询速度肯定快,但这样的索引会比较难看,且占空间,影响更新速度。因为你select 的 是 *...你include的会很多,这就是为什么老说能不select*时就不要这么写的一个原因。
但是,如果你的结果集占比很小,就不必这样改了,这个执行计划就是最优的了。

#15


谢谢 roy_88 的持续关注和分析。

谢谢 spiritofdragon 详细解释,解释的非常清晰!

再次感谢! 为什么有的执行计划中没有“Seek谓词”(都属于索引查找)?

#1


另外问一下,由于必须用到 AND 和 OR 的组合,导致索引查询失效,我可以用 UNION  ALL 分开写成2次查询,问题是:
用 UNION  AL 分开2次查询速度快,还是舍弃部分索引速度快(我用的复合索引,至少前3个是可以用上的)?

#2


如果没有 Seek 谓词 字样,索引查找用上了吗?
----
没有用上,是否需要用要看执行成本,表太小或查询结果集占用50%以上的数据时,数据库会用表扫描
是不是显示 Table Scan--这开销成本是比较大的

这两列是不是没有建索引,没有时建上
FromHour
ToHour

#3


看执行计划时要留意有没有并行,有并行的情况性能是更优的

#4


引用 2 楼 roy_88 的回复:
如果没有 Seek 谓词 字样,索引查找用上了吗?
----
没有用上,是否需要用要看执行成本,表太小或查询结果集占用50%以上的数据时,数据库会用表扫描
是不是显示 Table Scan--这开销成本是比较大的

这两列是不是没有建索引,没有时建上
FromHour
ToHour


我是建的复合索引:
b, c, d, h, m, LimitRange, FromHour, ToHour

顺序也没有问题,是不是 FromHour <= xxx 无法用索引?

另外,如何看有没有并行?执行计划中的箭头分叉就是并行吗?

#5


引用 4 楼 oldhunter 的回复:
Quote: 引用 2 楼 roy_88 的回复:

如果没有 Seek 谓词 字样,索引查找用上了吗?
----
没有用上,是否需要用要看执行成本,表太小或查询结果集占用50%以上的数据时,数据库会用表扫描
是不是显示 Table Scan--这开销成本是比较大的

这两列是不是没有建索引,没有时建上
FromHour
ToHour


我是建的复合索引:
b, c, d, h, m, LimitRange, FromHour, ToHour

顺序也没有问题,是不是 FromHour <= xxx 无法用索引?

另外,如何看有没有并行?执行计划中的箭头分叉就是并行吗?


你最好贴出执行步骤或执行计划图?看你的语句是不会出现你所说的情况

会出现,那是你查询条件大概占用表数>=50%左右或<0.8%左右时会用到表扫描,具体占用比例各版本可能有所区别

#6



确实,这次有谓词了,不过为什么FromHour索引没有用上?

--这个有“Seek谓词”
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 0
 
--现在都有“Seek谓词”,但为什么FromHour索引没有用上?
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 1
AND FromHour <= DATEPART(HH, GETDATE()) AND DATEPART(HH, GETDATE()) <= ToHour


#7


引用 6 楼 oldhunter 的回复:
确实,这次有谓词了,不过为什么FromHour索引没有用上?

--这个有“Seek谓词”
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 0
 
--现在都有“Seek谓词”,但为什么FromHour索引没有用上?
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 1
AND FromHour <= DATEPART(HH, GETDATE()) AND DATEPART(HH, GETDATE()) <= ToHour

按你贴出来的语句会用上,你能贴出你的执行计划不?这样的问题没法猜
特定情况下开销成本大时不会用上或索引与条件不合理时会用不上

#8


下面分别是执行计划、索引列,以及建表的SQL。您看一下,为什么FromHour没有用上索引?

为什么有的执行计划中没有“Seek谓词”(都属于索引查找)?
为什么有的执行计划中没有“Seek谓词”(都属于索引查找)?

CREATE TABLE [dbo].[t](
[id] [int] IDENTITY(1,1) NOT NULL,
[a] [int] NOT NULL,
[b] [bit] NOT NULL,
[c] [tinyint] NOT NULL,
[d] [int] NOT NULL,
[h] [int] NOT NULL,
[m] [int] NOT NULL,
[LimitRange] [bit] NOT NULL,
[FromHour] [int] NOT NULL,
[ToHour] [int] NOT NULL,
[LastTime] [datetime] NULL,
 CONSTRAINT [PK_t] PRIMARY KEY CLUSTERED 
(
[id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleEnabled]  DEFAULT ((0)) FOR [b]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleMode]  DEFAULT ((0)) FOR [c]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleDays]  DEFAULT ((0)) FOR [d]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleHours]  DEFAULT ((0)) FOR [h]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleMinutes]  DEFAULT ((0)) FOR [m]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleLimitTimeRange]  DEFAULT ((0)) FOR [LimitRange]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleFromHour]  DEFAULT ((0)) FOR [FromHour]
GO

ALTER TABLE [dbo].[t] ADD  CONSTRAINT [DF_t_ScheduleToHour]  DEFAULT ((23)) FOR [ToHour]
GO


declare @count int = 1;
while @count < 1000
begin
insert into t (a, b, c, LimitRange)
values (1, 1, 1, 1)
set @count = @count + 1
end

#9


引用 7楼中国风 的回复:
Quote: 引用 6 楼 oldhunter 的回复:


确实,这次有谓词了,不过为什么FromHour索引没有用上?

--这个有“Seek谓词”
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 0
 
--现在都有“Seek谓词”,但为什么FromHour索引没有用上?
SELECT * FROM t WHERE a = 1 AND b = 1
AND c = 0
AND d = DAY(GETDATE()) AND h = DATEPART(HH, GETDATE()) AND m = DATEPART(MI, GETDATE())
AND LimitRange = 1
AND FromHour <= DATEPART(HH, GETDATE()) AND DATEPART(HH, GETDATE()) <= ToHour

按你贴出来的语句会用上,你能贴出你的执行计划不?这样的问题没法猜
特定情况下开销成本大时不会用上或索引与条件不合理时会用不上
up

#10


执行计划属于,有序聚集索引+非聚集索引查找
执行计划没问题,有用到索引,最后条件是固定值 和范围值要计算开始位置是分开的,执行计划是 index seek 不可能是index Scan(这是范围查找)

如果没有用到索引会显示,条件执行计划会显示在聚集索引分支上


#11


引用 10楼中国风 的回复:
执行计划属于,有序聚集索引+非聚集索引查找
执行计划没问题,有用到索引,最后条件是固定值 和范围值要计算开始位置是分开的,执行计划是 index seek 不可能是index Scan(这是范围查找)

如果没有用到索引会显示,条件执行计划会显示在聚集索引分支上
seek谓词中没有出现 FromHour,是不是表示 FromHour 没有参与 index seek?

#12


引用 11楼我是你的主体 的回复:
Quote: 引用 10楼中国风 的回复:
执行计划属于,有序聚集索引+非聚集索引查找
执行计划没问题,有用到索引,最后条件是固定值 和范围值要计算开始位置是分开的,执行计划是 index seek 不可能是index Scan(这是范围查找)

如果没有用到索引会显示,条件执行计划会显示在聚集索引分支上
seek谓词中没有出现 FromHour,是不是表示 FromHour 没有参与 index seek?
up

#13


引用 11 楼 oldhunter 的回复:
Quote: 引用 10楼中国风 的回复:
执行计划属于,有序聚集索引+非聚集索引查找
执行计划没问题,有用到索引,最后条件是固定值 和范围值要计算开始位置是分开的,执行计划是 index seek 不可能是index Scan(这是范围查找)

如果没有用到索引会显示,条件执行计划会显示在聚集索引分支上
seek谓词中没有出现 FromHour,是不是表示 FromHour 没有参与 index seek?


没用到非聚集索引时,会用聚集索引查找或扫描或堆扫描(开销会大,执行计划占用成本会有显示)

#14


我来说个观察后的推测结论。大家认为不对可以指出。
你的图片里(截图都不截全,太小家子气了。开玩笑哈)。你的执行计划有索引查找,但还有“键查找”,出现这个“键查找”说明,你虽然用到了索引,但该索引没有覆盖(include)好的你的select字段。当你的查找结果占整表占比比较小时,这个速度还是比scan快。但是,如果占比比较大时,(版主说的50%都算是客气的),估计20%(我也是随便估的)就算大了。这时,索引查找+键查找的速度估计还没有聚集索引扫描快(即不用索引而全表扫描)。当然,如果这种情况,优化器大多时会自动把执行计划变成"聚集索引扫描"。但你的执行计划没变说明,你的结果集没有到这种程度,或者,优化器没有通过统计信息得出正确的执行预算。那么,你还要“频繁”使用上面的语句的话,你把所有select的字段,都放进include里,创建覆盖索引,就不会出现键查找了,查询速度肯定快,但这样的索引会比较难看,且占空间,影响更新速度。因为你select 的 是 *...你include的会很多,这就是为什么老说能不select*时就不要这么写的一个原因。
但是,如果你的结果集占比很小,就不必这样改了,这个执行计划就是最优的了。

#15


谢谢 roy_88 的持续关注和分析。

谢谢 spiritofdragon 详细解释,解释的非常清晰!

再次感谢! 为什么有的执行计划中没有“Seek谓词”(都属于索引查找)?