Sql-Server

確定 SHRINKDATABASE 將從哪些對像中釋放空間

  • July 18, 2017

首先,是的,收縮是不好的。永遠不要使用它。我明白。不幸的是,這是一種標準操作程序,我無法爭論,因為它通常是權宜之計,直到我們可以獲得維護視窗來分配更多空間並重建/重組索引。

我們最近遇到了一個問題,我們從傳統備份切換到第三方工具。由於數據庫的大小和我們最近刪除的一些大型對象,在轉換之前使用新工具進行乾淨備份之前縮小它是有意義的。我有一些保留意見,但我們繼續進行,因為它很少引起問題。顯然,清除日誌並不是真正的問題,但我們正在縮小 mdf。這對一些大型的、高度事務性的對象造成了很多阻塞,並且正確地提出了一些關於我們如何使用它的非常嚴重的問題。

我一直在做很多研究,但還沒有找到足夠讓我滿意的細節。

  • 是否有任何地方真正描述了 SHRINK 的運作方式?
  • 有沒有辦法確定哪些對像比其他對象更碎片化,以及它如何釋放空間?或者,與數據庫中的其他人相比,表的碎片程度更重要,它更多的是關於對象的整體大小嗎?

Paul Randall在這裡談了一點,但還不夠詳細。

我知道您可以將其基於 dm 索引統計資訊,但由於大小和過度索引,在我們的一些較大的數據庫上執行非常困難。我也不確定這是否是我需要關心的全部。主表儲存為堆,只有索引真正碎片化,但我不確定不同的分區如何影響事物,或者底層數據庫的其他部分是否也可以被釋放。

我確實也看到了這個問題,但我不確定我是否能夠將它配置為我們正在尋找的那種粒度。

一些想法:

1.永遠不要用SHRINKDATABASE,永遠用SHRINKFILE

您希望控制它從哪個文件佔用空間,以及確切佔用多少空間,以便您保留一些空間。執行這樣的查詢以查看每個文件中的實際使用/可用空間:

SELECT DB_NAME() as dbname, type_desc, name as logical_name, 
   CONVERT(decimal(12,1),size/128.0) as TotalMB,
   CONVERT(decimal(12,1),FILEPROPERTY(name,'SpaceUsed')/128.0) as UsedMB,
   CONVERT(decimal(12,1),(size - FILEPROPERTY(name,'SpaceUsed'))/128.0) as FreeMB,
   physical_name
FROM sys.database_files WITH (NOLOCK)
ORDER BY type, file_id;

假設您的主數據文件為 100GB,但實際只使用了 20GB,您可能有 25GB 或 30GB 的最終目標大小以留出一些內部可用空間。所以你會做一個收縮,比如:

DBCC SHRINKFILE (name='logical_name', size=30000)

2. 內部SHRINKFILE行為

在內部,縮小數據文件只是將已使用的頁面從文件末尾一次一個地移動到開頭附近的一個開放位置,直到文件末尾有足夠的空間來滿足您的目標大小。

這是一種相當簡單的暴力破解方法,不關注頁面內容,這就是為什麼它經常導致表格碎片的原因。從您連結的Paul Randal 文章中:

數據文件收縮操作一次對單個文件進行,並使用 GAM 點陣圖查找文件中分配的最高頁。然後,它會盡可能地將其移向文件的前面,依此類推。

如果它要移動的頁面被另一個程序鎖定,它將被阻塞。

3. SHRINKS 保持進步

如果您開始收縮,然後由於阻塞或其他衝突活動而不得不停止它,它將保留其進度。它成功移動的所有頁面都將保持移動狀態。您可以稍後恢復以完成工作。

4.找出哪些表會受到收縮的影響

實際上可能有一些方法可以做到這一點,使用查詢sys.allocation_unitssys.partitions可能使用DBCC PAGE或其他東西,但我的建議是:不要打擾,大型數據庫將在數據文件中包含數千個對象的分散殘餘,其中大部分是你不在乎。

如果你堅持,這裡有一些我通過搜尋找到的高級文章:

當它開始阻塞時,您已經可以找出哪些表/索引在起作用,其他一切都是噪音。

如果該鎖定永遠不會清除以使您有機會移動頁面,那麼您可能必須安排一些停機時間而沒有其他活動。

5. 完成後,進行重新索引以修復碎片

數據文件可能會再次增長一點,但除非您的數據庫是一個巨大的表,否則您可能仍然會得到比開始時更小的最終結果。

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