38

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

指数:

/****** 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]
4

9 回答 9

27

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

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

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

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

于 2009-12-28T19:22:36.857 回答
17

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

考虑以下查询:

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 server 有了一个新的选项。它可以选择使用非聚集索引进行查找,这将产生 State='TX' 的行。但是,为了让剩余的列在 SELECT 中返回,它必须通过对每一行执行聚集索引查找来查找这些列。

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

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

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

于 2013-01-30T06:59:56.793 回答
9

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

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

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

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

于 2009-12-28T19:59:59.767 回答
3

想法...

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

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

  • 最后,为什么 FILLFACTOR 80%?

编辑:

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

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

于 2009-12-28T19:28:19.717 回答
3

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

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

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

于 2009-12-28T20:32:10.027 回答
2

如果您硬编码WHERE标准会发生什么,如下所示:

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

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

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

于 2009-12-28T19:56:58.473 回答
1

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

于 2009-12-28T19:20:28.000 回答
1

检查索引静态。

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

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

于 2017-05-04T07:31:42.743 回答
0

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

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

于 2009-12-28T19:22:26.473 回答