[英]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 行的聚集索引范围查找不是您的问题。
从技术上讲,您可以通过使聚集索引变窄来提高搜索性能:
两者都可以对范围搜索时间产生相当大的影响,因为它们减少了 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.