我目前正在使用 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
我的应用程序得到供应商的支持,我一直在与他们沟通以将这些堆更改为表并创建聚集索引,但是它还没有产生任何有意义的结果,因为他们已经将主键定义为唯一的非聚集索引并且它也是一部分外键,因此在进行任何更改之前需要在多个级别进行更改。首先,我花了很多天来解释聚簇索引和带唯一索引的主键的区别。
我还经历了Brent Ozar 先生建议的调整,以更改 Ola Hallengren 先生为索引优化提供的脚本中的默认值,以提高效率,但是我没有找到堆重建的任何细节。
根据我的理解,堆的碎片可以通过此处描述的两种方式处理:
- 在表上创建聚簇索引并将其删除——这将清除所有碎片并重建所有非聚簇索引,但这会耗费时间和 I/O。
- 重建堆——这也将清除碎片并重建表重建的所有非聚集索引部分。
我不能选择选项 1,因为我不知道可以创建聚集索引的列,而且这可能比选项 2 花费的时间更长。
我正在寻找通过 Ola Hallengren 在脚本中实现选项 1 的可能性或处理此问题的替代方法。另外要补充的是,只有当堆的大小超过 10,000 页且碎片级别超过 80 时,我才想重建我的堆。
我使用的是 Microsoft SQL Server 2014 SP3 企业版。
作为一名 DBA - 我不喜欢在我的数据库中使用堆,但是因为它是供应商支持的应用程序,并且因为他们已经将主键定义为唯一索引并且这些键是外键,所以很难将它们更改为集群,因为参考以及停机时间的可能性。
编辑:我浏览了 Erik Darling 先生提供的链接,我可以确认我有很多堆在数据库中转发记录或删除。现在,我回到了我开始的地方,即这两个选项。正如我之前提到的,在我的场景中创建聚簇索引非常困难,并且考虑到复杂的外键结构,至少需要数月(乐观)并且可能会停机。需要有关重建堆和可能的副作用的建议。
堆有一些您无法通过聚簇索引遇到的特殊挑战:
我建议对您的数据库运行sp_BlitzIndex以查明这些情况是否与您的堆有关。如果没有,那就让他们一个人呆着。如果是,您可能需要考虑重建它们。
这时,你不能重组一个Heap表,重建一个Heap表也会重建它上面的任何非聚集索引。删除它们,重建堆表,然后重新创建非聚集索引可能更便宜。
您可以在此处阅读有关此内容的更多信息: