Sql-Server

從半滿的巨大 FG 中回收空間,其中包含分區和 LOB 數據

  • December 16, 2021

我們有一個包含多個文件組的數據庫。其中,有 4 個文件組(非主)包含大部分數據。這些文件組有分區表。它還包含 LOB 數據。

現在根據客戶的要求,我們已經清除了 50% 的數據。正因為如此,這 4 個文件組是半空的。例如,這些 FG 每個 400 GB,大約 200 GB 是免費的。

我的要求是從這 4 個 FG 中回收空間,因為我們預計它在不久的將來不會增長那麼多。收縮不是一種選擇,因為它很耗時。任何其他更快的方法來做到這一點。

有人可以幫幫我嗎。提前致謝。

收縮的耗時部分是將數據從文件的後半部分移到靠近開頭的空間中,以便可以截斷後半部分,您必須在回收空間之前移動數據,因為 SQL Server 不支持稀疏文件(它不能只告訴作業系統“我不需要那個位,現在可以隨意將它分配到其他地方”)。這意味著您無法就地執行任何更快的操作。

不過,您可能很幸運,發現文件的大部分後端都是空的,您可以簡單地截斷它們以釋放一些空間給文件系統 ( DBCC SHRINKFILE (<file>, TRUNCATEONLY);)。

您可以將數據遷移到新的文件組,然後刪除現有的文件組。但是,如果您在同一卷上執行此操作,鑑於您嘗試釋放 50% 或更少,這不會更快,並且可能會慢得多(它必須將 200Gb 移動到新文件,其中縮小最多會移動 200Gb文件)。如果您在卷之間執行此操作,但如果您使用基於旋轉磁碟的媒體,您可能會看到這項工作要快得多,因為與收縮相比,磁頭移動延遲可能要少得多。如果您使用的是低延遲儲存,則此好處不會很顯著。

收縮不是一種選擇,因為它很耗時。

需要注意的一點是,收縮實際上是一個可恢復的過程 - 如果您在中途停止它,您不會因為回滾而失去所有進度。因此,如果您有較短的維護視窗,您可以接受執行收縮操作對性能的影響,您可以啟動該過程並在視窗結束時取消它,並在下次重新啟動它。這可能需要幾個這樣的視窗,但最終會完成工作。

另一個要提到的問題是文件組之間的收縮和移動數據都在頁面級別工作,因此不會釋放內部未分配的空間頁。如果大多數空閒數據是頁外 LOB,這對您來說不太可能是一個大問題,但是如果刪除了少量行數據,您可能希望重建索引(以及堆,尤其是堆,如果您有沒有聚集索引的任何此類表)在收縮/遷移數據之前。您甚至可能會發現這將有效地將數據大部分移動到文件的前面,從而使您可以顯著截斷它們而無需進行完全重新排列和縮小。根據您的 SQL Server 版本和版本,您可以使用可恢復的聯機索引重建來將此過程拆分為多個維護時段,如上述收縮操作所述。

我想補充一下大衛的回答,有些事情會導致收縮需要很長時間。這裡有一些事情,在我的腦海中:

高球。對於移動的每個 LOB 頁面,您將進行一次表掃描。是的,你沒有看錯。每個移動的日誌頁面的表掃描。這是因為 SQL Server 不知道這個 LOB 頁面屬於哪一行(沒有反向指針)。

堆。當您在堆中移動數據頁時,該頁上的所有行都會獲得一個新的 RID。這導致所有的 NC 索引都需要使用這個新版本進行更新。即,所有 NC 索引,以及此堆頁上的每一行的此類更新。

阻塞。Shrink 需要一個 X 鎖(我相信它是),它會永遠等待。

我並不是說遷移到一個新的文件組一定更好,因為它也有缺點(正如大衛所提到的)。因此,最終由您決定哪種方法對您更有吸引力。Shrink 絕對是最簡單的一種,但可能需要很長時間。

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