我应该什么时候重建索引?

Nic*_*mas 60 sql-server index-maintenance

我应该什么时候重建我的关系数据库 (SQL Server) 中的索引?

是否有定期重建索引的情况?

Mat*_*t M 44

冒着在我的回答中过于笼统的风险,我会说您应该定期运行索引维护过程。但是,您的索引维护过程应该只重建/重组特别需要它的索引。

这就提出了一个问题:什么时候需要重建或重组索引?罗兰多很好地谈到了这一点。再一次,我冒着非常广泛的风险。当碎片级别对性能产生不利影响时,索引需要维护。这种碎片化程度可能因索引的大小和组成而异。

对于 SQL Server,我倾向于选择索引大小和索引碎片级别,然后开始执行索引维护。如果索引包含少于 100 页,我将不进行维护。

如果一个索引的碎片化程度在 10% 到 30% 之间,我将REORGANIZE列出索引和UPDATE统计信息。如果索引超过 30% 的碎片,我将REBUILD索引 - 没有UPDATE STATISTICS,因为这由REBUILD. 请记住,重建仅更新与索引直接关联的统计对象。其他列统计信息需要单独维护。

这个答案真的只是说得很长:是的,您应该进行日常索引维护,但仅限于需要它的索引。


Nic*_*mas 20

我应该什么时候重建我的关系数据库(例如 SQL Server)中的索引?

当索引因特殊事件而变得高度碎片化时,您应该重建索引。例如,您将大量数据加载到索引表中。

是否有定期重建索引的情况?

那么,如果您的索引由于定期活动而定期变得碎片化怎么办?您应该安排定期重建吗?他们应该多久跑一次?

Tom Kyte在这个经典的 Ask Tom 线程中,建议:

索引重建之间的时间延迟应该大约是 FOREVER。

...

不知道怎么说更好——索引要大而肥,有额外的空间。它位于您更新的列上——将索引条目从一个位置移动到另一个位置。一天该行的代码为“A”,第二天代码为“G”,然后是“Z”,然后是“H”,依此类推。因此该行的索引条目在索引中从一个地方移动到另一个地方。当它这样做时,它需要空间——如果空间不存在,我们会将块分成两部分——并腾出空间。现在指数越来越胖。随着时间的推移,索引的大小是您开始时的 2-3 倍,并且是“一半或更多的空”但是因为您移动行,所以没关系。现在,当我们四处移动行时,我们不再需要拆分块来腾出空间——房间已经可用了。

然后你来重建或删除并重新创建索引(具有相同的效果 - 只是重建“更安全” - 不会丢失索引并且可以更快,因为索引可以通过以下方式重建扫描现有索引而不是扫描表并排序和构建新索引)。现在,所有这些美好的空间都消失了。我们重新开始分割块的过程——让我们回到我们开始的地方。

你没有节省空间。

索引又回到了原来的样子。

您只会浪费时间重新构建它,从而导致这种恶性循环重演。

这里的逻辑是合理的,但它偏向于读取繁重的负载配置文件。

“胖”索引(即有很多间隙的索引)确实为新行和移动行保留了大量空间,从而减少了页面拆分并保持写入速度。但是,当您从该胖索引中读取数据时,您将必须阅读更多页面才能获得相同的数据,因为您现在正在筛选更多的空白空间。这会减慢您的阅读速度。

因此,在读取繁重的数据库中,您希望定期重建或重新组织索引。(频率如何以及在什么条件下?Matt M 已经对这个问题给出了具体的答案。)在读写活动大致相当的数据库中,或者在大量写入的数据库中,您可能会通过重建索引来损害数据库的性能经常。


mrd*_*nny 11

大多数人会定期重建它们,以免它们变得支离破碎。何时需要重建它们取决于它们碎片化的速度。一些索引需要经常重建,其他的基本上从不。查看SQLFool放在一起的脚本,该脚本可以为您处理很多问题。


小智 9

正如 Matt M 接受的答案中所指出的,一个常见的经验法则是应该重建超过 30% 碎片的索引。

此查询将帮助您找到碎片化程度超过 30% 的索引数量(如果有,您应该重建它们):

SELECT DB_NAME() AS DBName,
       OBJECT_NAME(ind.object_id) AS TableName,
       ind.name AS IndexName,
       indexstats.index_type_desc AS IndexType,
       indexstats.avg_fragmentation_in_percent,
       indexstats.fragment_count,
       indexstats.avg_fragment_size_in_pages,
       SUM(p.rows) AS Rows 
  FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
         INNER JOIN sys.indexes AS ind ON (    ind.object_id = indexstats.object_id
                                           AND ind.index_id = indexstats.index_id)
         INNER JOIN sys.partitions AS p ON (    ind.object_id = p.object_id
                                            AND ind.index_id = p.index_id)
 WHERE indexstats.avg_fragmentation_in_percent > 30
 GROUP BY
       OBJECT_NAME(ind.object_id),
       ind.name,
       indexstats.index_type_desc,
       indexstats.avg_fragmentation_in_percent,
       indexstats.fragment_count,
       indexstats.avg_fragment_size_in_pages 
 ORDER BY indexstats.avg_fragmentation_in_percent DESC
Run Code Online (Sandbox Code Playgroud)

  • @LowlyDBA - 它可能有点简洁,但我确实认为它回答了这个问题,并为讨论提供了一些有用的东西。我已经扩展了一点来解释如何。Amanda - 如果我的编辑看起来不正确,请随时回滚! (4认同)

小智 5

我应该什么时候重建索引?

当索引碎片百分比超过 30% 时。

是否有定期重建索引的情况?

没有这种情况,但一般情况下,每周做一次索引维护,周末是保持环境稳定的最佳做法。

我建议使用 Ola Hallengren 的维护脚本(最佳维护脚本),根据您的环境自定义脚本并安排它们在周末运行。

https://ola.hallengren.com/

注意:重建索引后请不要忘记更新统计信息,因为重建索引不会更新所有统计信息。

  • 我很确定你的笔记是不正确的。索引重建会更新统计信息。索引重组不会。虽然它只更新与索引相关的对象的统计信息,而不是所有的统计信息。话虽如此,我还是建议经常更新统计信息,以减少由于参数嗅探和过时的统计信息导致的糟糕查询计划而导致速度减慢的可能性。 (3认同)