Sql-Server

堆的碎片級別

  • March 18, 2019

我目前正在使用 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 先生提供的用於索引優化的腳本的預設值,以提高效率,但是我沒有找到堆重建的任何細節。

根據我的理解,堆的碎片可以通過兩種方式處理,如下所述

  1. 在表上創建聚集索引並將其刪除 - 這將清除所有碎片並重建所有非聚集索引,但這會耗費時間和 I/O。
  2. 重建堆 - 這也將清除碎片並重建表重建的所有非聚集索引部分。

我不能選擇選項 1,因為我不知道可以創建聚集索引的列,而且這可能需要比選項 2 更長的時間。

我正在尋找在 Ola Hallengren 的腳本中實現選項 1 的可能性或處理此問題的替代方法。另外要補充一點,只有當堆大小超過 10,000 頁且碎片級別超過 80 時,我才想重建我的堆。

我正在使用 Microsoft SQL Server 2014 SP3 企業版。

作為 DBA - 我不喜歡在我的數據庫中有堆,但是因為它是供應商支持的應用程序,並且由於他們已經將主鍵定義為唯一索引並且這些鍵是外鍵,因此很難將它們更改為集群由於參考以及停機時間的可能性。

編輯:我瀏覽了 Erik Darling 先生提供的連結,我可以確認我在數據庫中有許多帶有轉發記錄或刪除的堆。現在,我又回到了我開始的地方,即這兩個選項。正如我之前提到的,在我的場景中創建聚集索引非常困難,考慮到復雜的外鍵結構,至少需要幾個月(樂觀)並且可能會停機。需要有關重建堆和可能的副作用的建議。

堆有一些使用聚集索引無法體驗的特殊挑戰:

  • 轉發記錄
  • 強制頁面

我建議對您的數據庫執行sp_BlitzIndex,以了解您的堆是否正在發生這些事情。如果沒有,那就別管他們了。如果是,您可能需要考慮重建它們。

這時候,你不能重新組織一個 Heap 表,重建一個 Heap 表也會重建它上面的任何非聚集索引。刪除它們,重建堆表,然後重新創建非聚集索引可能更便宜。

您可以在此處閱讀有關此內容的更多資訊:

引用自:https://dba.stackexchange.com/questions/232357