繁体   English   中英

如何提高聚集索引查找的性能

[英]How to improve performance on a clustered index seek

我正在尝试提高运行非常缓慢的查询的性能。 通过实际执行计划后 我发现聚集索引搜索占用了 82%。 有什么办法可以提高索引查找的性能吗?

索引:

/****** Object:  Index [IX_Stu]    Script Date: 12/28/2009 11:11:43 ******/
CREATE CLUSTERED INDEX [IX_Stu] ON [dbo].[stu] 
(
 [StuKey] ASC
)WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]

表(为简洁起见省略了一些列):

CREATE TABLE [dbo].[stu](
 [StuCertKey] [int] IDENTITY(1,1) NOT NULL,
 [StuKey] [int] NULL
 CONSTRAINT [PK_Stu] PRIMARY KEY NONCLUSTERED 
(
 [StuCertKey] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]

我在这里概括,但是......

在大多数情况下,聚集索引查找是最好的情况。 我能想到的提高性能的唯一方法是:

  • 如果可能,更新查询以返回更少的行/列;
  • 对索引进行碎片整理或重建;
  • 跨多个磁盘/服务器对索引进行分区。

如果它只返回 138 行,而且速度很慢……也许它被其他进程阻止了? 您是单独进行测试,还是其他用户/进程同时在线? 或者甚至可能是硬件问题,例如磁盘故障。

聚集索引查找发生在使用非聚集索引并且不一定是坏的。

考虑以下查询:

SELECT s.StuKey, s.Name, s.Address, s.City, s.State FROM stu s WHERE State='TX'

如果 StuKey 上只有一个聚集索引,那么 Sql Server 只有 1 个选项,它必须扫描整个表寻找 State="TX" 的行并返回这些行。

如果在 State 上添加非聚集索引

CREATE INDEX IX_Stu_State on Stu (State)

现在 Sql 服务器有一个新选项。 它可以选择使用非聚集索引进行查找,这将产生 State='TX' 的行。 但是,为了让剩余的列在 SELECT 中返回,它必须通过对每一行进行聚集索引查找来查找这些列。

如果您想减少聚集索引搜索,那么您可以通过在索引中包含额外的列来“覆盖”索引。

 CREATE INDEX IX_Stu_State2 on Stu (State) INCLUDE (name, address, city )

该索引现在包含回答上述查询所需的所有列。 查询将执行索引查找以仅返回 State='TX' 的行,并且可以从非聚集索引中拉出额外的列,因此聚集索引查找消失。

返回 138 行的聚集索引范围查找不是您的问题。

从技术上讲,您可以通过使聚集索引变窄来提高搜索性能:

  • 通过将“行外大值类型”设置为 1 并从头开始重新创建表,将所有 varlenght 转移到单独的分配单元中)。
  • 启用页面压缩(仅限 SQL 2008 EE)。

两者都可以对范围搜索时间产生相当大的影响,因为它们减少了 IO 和命中物理读取的需要。 当然,通常情况下,结果会因许多其他因素而异,例如您投影哪些列(将投影列驱逐到 BLOB 分配单元实际上可能会对某些查询产生不利影响)。 作为旁注,通常碎片对这种短距离扫描的影响很小。 再次,这取决于。

但正如我所说,我非常怀疑这是你真正的问题。 您只发布了计划的选定部分和您自己的分析结果。 真正的根本原因可能完全在别处。

想法...

  • 为什么 IX_Stu 是集群的? 在内部,SQL Server 向非唯一聚集索引添加了一个 4 字节的“唯一标识符”。 理由是什么? 这也会让你的 PK 变得臃肿

  • 您正在运行的实际查询是什么?

  • 最后,为什么 FILLFACTOR 80%?

编辑:

  • “正常” FILLFACTOR 将是 90%,但这只是一个经验法则

  • 一个 11 连接查询? 这很可能是你的问题。 您的 JOIN、WHERE 子句等是什么? 什么是全文计划?

一些一般性建议:当我必须进行查询优化时,我首先写出我认为执行计划应该是什么。

一旦我决定了我认为的执行计划应该是什么,我就会尝试使实际查询适合这个计划。 执行此操作的技术对于每个 DBMS 都不同,并且不一定从一个转移到另一个,甚至有时在不同版本的 DBMS 之间转移。

需要记住的是,DBMS 一次只能执行一个连接:它从两个初始表开始,连接它们,然后获取该操作的结果并将其连接到下一个表。 每个步骤的目标是最小化中间结果集中的行数(更准确地说,是最小化必须读取以生成中间结果的块数,但这通常意味着最少的行)。

如果您对WHERE条件进行硬编码,会发生什么情况,如下所示:

SELECT StuCertKey, StuKey FROM stu 
WHERE stuKey in (/* list 50 values of StuKey here */)

如果它仍然很慢,则说明存在某种内部问题。 如果它更快,那么索引就不是您的瓶颈,而是您为创建WHERE过滤器所做的JOIN

请注意,如果有很多大列,尤其是有 BLOB 时, SELECT *可能会非常慢。

您是否尝试过对该索引进行一些维护? 喜欢碎片整理吗? 花费那么多(120.381)似乎真的很奇怪。 索引查找是最快的索引操作,不应该花那么长时间。 你可以发布查询吗?

检查索引静态。

重新计算聚集索引统计信息将解决问题。

就我而言,我正在寻找 40M 中的 30 条记录。 执行计划说它正在通过聚集索引,但花了大约 200 毫秒。 并且索引没有进行碎片整理。 重新计算它的统计信息后,它在 10 毫秒内完成!

重建索引,并计算统计数据?

我能想到的加速它的唯一另一种方法是对表进行分区,这可能也可能不可能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM