Sql-Server

堆上的壓縮

  • August 9, 2019

以下是Microsoft Docs中的一段:

作為 DML 操作的一部分,在堆中分配的新頁面在重建堆之前不會使用 PAGE 壓縮。通過刪除和重新應用壓縮或者通過創建和刪除聚集索引來重建堆。

我不明白為什麼會這樣。如果我有一個具有指定壓縮設置的堆,為什麼不將它應用於屬於該表的頁面?

謝謝

雖然我不知道導致差異的具體內部機制,但我可以說堆的管理(內部)與聚集索引(可能還有非聚集索引)略有不同:

  • 從堆中刪除行以使一個或多個數據頁為空(未分配行)並不一定會釋放該空間。您可能需要在表上創建然後刪除聚集索引,或者呼叫ALTER TABLE [TableName] REBUILD;(從 SQL Server 2014 開始?)。有關更多詳細資訊和選項,請參閱 Microsoft Docs 頁面以了解DELETE
  • 將單獨的行(即不是基於集合的INSERT)插入堆中不會像使用聚集索引那樣完全填充數據頁。只要行有空間(數據和行成本)加上插槽數組的 2 字節成本,聚集索引將適合行。然而,堆中的數據頁不使用頁面上剩餘的字節數,而是使用一個非常籠統的指標來指示頁面的填充程度,並且報告的級別並不多。級別大致為:0%、20%、50%、80% 和 100% 滿。並且它會切換到 100%,而仍有空間可容納另一行(事實上,如果在基於集合的操作中插入相同數量的行,那麼它會盡可能地填滿頁面)。當然,就像DELETE操作,重建堆將打包盡可能多的行,以適應數據頁。

現在考慮以下資訊,取自頁面壓縮實施的 Microsoft Docs 頁面的“頁面壓縮發生時”部分:

…隨著數據被添加到第一個數據頁,數據被行壓縮。…當頁面已滿時,要添加的下一行啟動頁面壓縮操作。審查整個頁面;…

因此,在寫入數據頁之前,它們需要 ALTER TABLE REBUILD、CREATE / DROP 或更改數據壓縮設置(所有這些都重建堆)似乎與其他堆行為完全一致最佳。如果 Heap 沒有完全意識到“整個頁面”(直到 Heap 被重建)並且不知道頁面何時肯定是滿的,那麼他們將不知道何時啟動頁面壓縮操作(在處理更新和單-行插入)。

另一個將進一步限制某些堆自動應用頁面壓縮(即使它們可以)的技術性是,應用壓縮將需要重建該堆的所有非聚集索引(如果存在)。正如“數據壓縮”的連結頁面還指出:

更改堆的壓縮設置需要重建表上的所有非聚集索引,以便它們具有指向堆中新行位置的指針。

所指的“指針”是行 ID (RID),它們是以下內容的組合:FileID、PageID 和頁面上的插槽/位置。這些 RID 被複製到非聚集索引中。作為一個精確的物理位置,它們有時比使用聚集索引鍵遍歷 b 樹更快。但是,物理位置的一個缺點是它可以改變,這就是這裡的問題。然而,聚集索引不會遇到這個問題,因為它們的鍵值被複製到非聚集索引中,作為返回聚集索引的指針。並且鍵值保持不變,即使它們的物理位置發生變化。

另見:

要重建堆以回收浪費的空間,請在堆上創建聚集索引,然後刪除該聚集索引。

當堆配置為頁面級壓縮時,頁面僅通過以下方式接收頁面級壓縮:

+ 數據是在啟用批量優化的情況下批量導入的。 + 使用 INSERT INTO … WITH (TABLOCK) 語法插入數據,並且該表沒有非聚集索引。 + 通過使用 PAGE 壓縮選項執行 ALTER TABLE … REBUILD 語句來重建表。

以及問題中引用的聲明。

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