堆的碎片级别

Lea*_*min 4 sql-server heap fragmentation sql-server-2014 ola-hallengren

我目前正在使用 Ola Hallengren 先生提供的脚本来执行维护工作,最近我注意到有很多表(堆)碎片级别高得惊人,需要查看并采取行动。我在网站上查看了常见问题解答,似乎他的脚本不支持重建堆。我使用以下查询来查找碎片级别:

SELECT dbschemas.[name] as 'Schema', 
dbtables.[name] as 'Table', 
dbindexes.[name] as 'Index',
indexstats.alloc_unit_type_desc,
indexstats.avg_fragmentation_in_percent,
indexstats.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
AND indexstats.index_id = dbindexes.index_id
WHERE indexstats.database_id = DB_ID() and dbindexes.name is null
ORDER BY page_count desc, indexstats.avg_fragmentation_in_percent desc
Run Code Online (Sandbox Code Playgroud)

我的应用程序得到供应商的支持,我一直在与他们沟通以将这些堆更改为表并创建聚集索引,但是它还没有产生任何有意义的结果,因为他们已将主键定义为唯一的非聚集索引并且它也是一部分外键,因此在进行任何更改之前需要在多个级别进行更改。首先,我花了很多天时间来解释聚集索引和具有唯一索引的主键之间的区别。

我还经历了Brent Ozar 先生建议的调整,以更改 Ola Hallengren 先生为索引优化提供的脚本中的默认值,以使其更高效,但是我没有找到任何堆重建的细节。

按我的理解堆的碎片可以通过两种方式所描述的处理在这里

  1. 在表上创建聚簇索引并将其删除 - 这将清除所有碎片并重建所有非聚簇索引,但这会耗费时间和 I/O。
  2. 重建堆 - 这也将清除碎片并重建表重建的所有非聚集索引部分。

我不能选择选项 1,因为我不知道可以创建聚集索引的列,而且这可能需要比选项 2 更长的时间。

我正在寻找在 Ola Hallengren 的脚本中实现选项 1 的可能性或处理此问题的替代方法。另外补充一点,我想只在堆大小超过 10,000 页且碎片级别超过 80 时重建我的堆。

我使用的是 Microsoft SQL Server 2014 SP3 企业版。

作为 DBA - 我不喜欢在我的数据库中有堆但是因为它是供应商支持的应用程序并且因为他们已经将主键定义为唯一索引并且这些键是外键,因此很难将它们更改为集群由于参考资料以及停机时间的可能性。

编辑:我浏览了Erik Darling 先生提供的链接,我可以确认我有许多带有转发记录或跨数据库删除的堆。现在,我回到我开始的地方,即这两个选项。正如我之前提到的,在我的场景中创建聚集索引是非常困难的,考虑到复杂的外键结构,至少需要几个月(乐观的)停机时间。需要有关重建堆和可能的副作用的建议。

Eri*_*ing 11

堆有一些特殊的挑战,您在使用聚簇索引时无法体验到这些挑战:

  • 转发记录
  • 俘虏页面

我建议对您的数据库运行sp_BlitzIndex以查明这些事情中的任何一个是否发生在您的堆上。如果没有,那就让他们一个人呆着。如果是,您可能需要考虑重建它们。

这时,你不能重新组织一个 Heap 表,重建一个 Heap 表也会在它上面重建任何非聚集索引。删除它们,重建堆表,然后重新创建非聚集索引可能更便宜。

您可以在此处阅读有关此内容的更多信息: