sqlserver group by 非聚集多字段组合索引性能慢的问题

表定义:

CREATE TABLE [his].[38] (
  [ID] int  IDENTITY(1,1) NOT NULL,
  [Time] datetime  NOT NULL,
  [ItemCode] int  NOT NULL,
  [AVG] float(53)  NOT NULL,
  [P1] float(53)  NULL,
  [P2] float(53)  NULL,
  [P3] float(53)  NULL,
  [P4] float(53)  NULL,
  CONSTRAINT [PK_HIS_38] PRIMARY KEY NONCLUSTERED ([ID])
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 [his].[38] SET (LOCK_ESCALATION = TABLE)
GO

CREATE NONCLUSTERED INDEX [IX_card_time]
ON [his].[38] (
  [Time] ASC
)
GO

CREATE NONCLUSTERED INDEX [Index_ItemCode_avg_time]
ON [his].[38] (
  [ItemCode] ASC,
  [AVG] ASC,
  [Time] ASC
)
GO

问题:

执行下面的查询:

SELECT 
  ItemCode, 
  max([AVG]) [MaxAVG], 
  max([Time]) [Time] 
from Resistance.his.[38] WITH(NOLOCK)
where 1 = 1
and time >= '2022-01-05 00:00:00'
and time <= '2022-01-12 23:59:59'
GROUP BY ItemCode

性能很慢。
解释执行计划中发现:走的是“索引扫描”。并非命中“索引查找”即未正确命中Index_ItemCode_avg_time

测试:

  1. 强制使用Index_ItemCode_avg_time
SELECT 
  ItemCode, 
  max([AVG]) [MaxAVG], 
  max([Time]) [Time] 
from Resistance.his.[38] WITH(INDEX(Index_ItemCode_avg_time), NOLOCK)
where 1 = 1
and time >= '2022-01-05 00:00:00'
and time <= '2022-01-12 23:59:59'
GROUP BY ItemCode

解释执行计划中发现:走的仍旧是“索引扫描”,说明我们建立的Index_ItemCode_avg_time有问题。

  1. 强制使用IX_card_time
SELECT 
  ItemCode, 
  max([AVG]) [MaxAVG], 
  max([Time]) [Time] 
from Resistance.his.[38] WITH(INDEX(IX_card_time), NOLOCK)
where 1 = 1
and time >= '2022-01-05 00:00:00'
and time <= '2022-01-12 23:59:59'
GROUP BY ItemCode

解释执行计划中发现:走的是“RID查找”
RID查找是什么呢?就是说sql先根据time条件字段“索引查找”然后再回去把其他字段查出来(这个过程叫RID查找)

思考:

从测试上来看,并结合查找相关资料,我们的多字段组合索引的顺序可能出了问题。
下面调整一下索引顺序:

-- 删除原索引
drop index Index_ItemCode_avg_time on [his].[38];

-- 新定义索引
CREATE NONCLUSTERED INDEX [Index_time_ItemCode_avg] ON [his].[38] 
(
  [Time] ASC,
  [ItemCode] ASC,
  [AVG] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY];

最后测试:

SELECT 
  ItemCode, 
  max([AVG]) [MaxAVG], 
  max([Time]) [Time] 
from Resistance.his.[38] WITH(NOLOCK)
where 1 = 1
and time >= '2022-01-05 00:00:00'
and time <= '2022-01-12 23:59:59'
GROUP BY ItemCode

解释执行计划中发现:走的是“索引查找”
解决。

image.png

小结:

多字段的组合索引在建立的时候要考虑两个问题:

  1. 要包含where条件字段、select查询字段(当然不能建立太多、太乱详细请自行研究);
  2. 顺序要正确!先where条件字段,后select查询字(我上面出现的问题原因就出在这)。

你可能感兴趣的:(sqlserver group by 非聚集多字段组合索引性能慢的问题)