Sql-Server

如何使用 nvarchar(max) 欄位壓縮不可收縮的表?

  • October 25, 2021

我們有一個嚴重的問題已經在我們的腦海中盤旋了將近兩個星期。我們有一個大數據庫(~250 GB,MS SQL Server 2014),我們需要以某種方式縮小它,因為我們的 SSD 快滿了。快速分析表明 1) 數據庫中幾乎沒有可用空間用於收縮操作,2) 我們在數據庫中有兩個非常大的表(約 95 GB,每個約 5M 條目)。數據庫正在被外部軟體(ERP 系統)使用,我們擁有從軟體端清理這些表所需的一切(這些表正被內部期刊使用,舊條目不是必需的),所以我們就這樣做了,導致約 2,7M 條目被刪除(實際上它們已被刪除,已通過查詢確認)。

但有一個問題 - 表的實際大小沒有改變。具有 2,3M 條目的表仍使用約 94 GB 的磁碟空間,幾乎與有 5M 條目時一樣。檢測到的用於收縮的可用空間量(數據庫和文件)也沒有改變。我從另一台伺服器上的新備份恢復數據庫,並嘗試重建,然後刪除和恢復聚集索引,但後來得知它不起作用,因為表有兩個nvarchar(max)欄位(這些欄位將 XML 數據和內部狀態儲存為字元串)。我還嘗試執行以下查詢作為實驗:

use uvs_experiment;

select * into _InfoRg3380Tmp from _InfoRg3380 where 1=2;

truncate table _InfoRg3380Tmp;

insert into _InfoRg3380Tmp select * from _InfoRg3380 where _Fld3382RRef = 0x80C7A4BF011CE3C311E847800C55C223;

此查詢試圖創建一個表,該表將儲存具有唯一一個,實際上是最有意義的狀態的條目。結果……是一樣的。新的目標表仍然使用大約 90GB 的空間,大約有 1,3M 的條目。請注意,表中幾乎所有的條目在欄位中都有一些數據(有時很重)nvarchar(max),排除的條目也不例外,即它不是之前刪除或被此查詢排除的空白條目。

之前和之後的表

這裡發生了什麼以及我們如何釋放一些空間?我知道這是 SQL Server 關於如何處理帶有nvarchar(max)欄位的頁面的一些非常奇怪的行為,但我們需要一個解決方案(除了將數據庫移動到另一台伺服器之外)。不幸的是,來自 SQL Server 2016+ 的 GZip 壓縮在這裡不是一個選項。

我們為 CCI 中的 LOB 添加了壓縮,正是針對 SQL 2016+ 中的這種情況。如果您無法升級,那麼您可能應該為伺服器獲得更多磁碟空間作為最簡單的解決方法。

回答一個老問題,但從 SQL 2016 開始,還有 COMPRESS() / DECOMPRESS() 函式。如果您不能更改應用程序的程式碼但允許更改架構,您可以

  • 使用 _compressed-suffix 創建一個新表
  • 將所有現有行插入其中,但使用 COMPRESS() 作為最大列
  • 刪除原始表
  • 創建一個具有原始名稱的視圖,該視圖呼叫 DECOMPRESS() 以返回原始內容
  • 在視圖上創建一個而不是插入/更新觸發器,將插入/更新重定向到 _compressed 表並再次使用 COMPRESS()

退稅:

  • 寫入性能較慢
  • 更多 CPU 使用率
  • 比較(等於或類似)壓縮列將非常慢(它必須解壓縮每一行)
  • 當您的供應商在實施新版本時嘗試更改表格時出現問題

理論上,您甚至可以在 SQL 2016 之前執行此操作,當您使用 clr 儲存過程來壓縮/解壓縮(CLR = 外部 DLL(例如 C#))時,但這會有更多的缺點。

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