很多時候,我們經常使用sp_spaceused來查看表的空間使用情況,上個月群里有個網友說他使用DELETE刪除了數據後,使用sp_spaceused查看,發現該表的分配的空間總量(reserved)與數據使用的空間總量(data)沒有變化,當時和他討論了並分析了一下原因,隨手記錄了一下這個案例,這... ...
很多時候,我們經常使用sp_spaceused來查看表的空間使用情況,上個月群里有個網友說他使用DELETE刪除了數據後,使用sp_spaceused查看,發現該表的分配的空間總量(reserved)與數據使用的空間總量(data)沒有變化,當時和他討論了並分析了一下原因,隨手記錄了一下這個案例,這個周末剛好有點時間,正好分析整理一下這個案例、分享在這篇文章。如下所示,我們先構造數據,我們的測試案例比較極端,剛剛保證每個頁面(page)剛好存儲兩條記錄。如下所示:
USE Test ;
GO
CREATE TABLE space_test
(
id INT,
name VARCHAR(4000)
)
GO
SET NOCOUNT ON;
Go
DECLARE @Index INT ;
SET @Index = 1;
WHILE @Index <= 10000
BEGIN
INSERT INTO dbo.space_test
SELECT @Index, REPLICATE(N'k', 4000);
SET @Index += 1;
END
EXEC sp_spaceused 'dbo.space_test'
接下來我們刪除了id為偶數的記錄。
DELETE dbo.space_test WHERE id %2=0
如下截圖所示,我們刪除了5000條記錄,還剩下5000條記錄,但是該表的分配的空間總量(reserved)與數據使用的空間總量(data)沒有變化,依然是40008KB和40000KB
我們刪除了一半記錄,照理說,數據使用的空間總量(data)應該變化了。那麼我使用DBCC SHOWCONTIG('space_test')來看看,如下截圖所示,
你會發現每頁的平均可用位元組數(Avg. Bytes Free per Page) 和平均頁密度(滿)(Avg. Page Density (full))出現了變化。如下對比所示:
|
Avg. Bytes Free per Page |
Avg. Page Density (full) |
刪除前 |
62 |
99.23% |
刪除後 |
4077.8 |
49.62% |
我們知道sp_spaceused的精確單位是頁。它是根據sys.allocation_units 和sys.partitions 這兩張管理視圖來計算存儲空間的。有時候,這兩張表可能不能及時反映出數據的準確信息。可以通過updateusage這個參數,要求SQL Server為這個指令更新管理視圖裡的統計信息。但是這個案例中,sp_spaceused不准確的原因並不是因為這兩張表沒有及時反映出數據的準確信息,而是實驗中按照特殊規律,在每一頁都刪除一條記錄,保留一條記錄,導致每一頁上釋放了接近一半的空間,並且頁的填充程度接近50%,從而出現頁面碎片化非常嚴重的情況,而sp_spaceused的精確單位是頁,從而導致這種特殊的情況出現。
其實這個倒沒有必要大驚小怪,這個空間雖然沒有釋放,但是下次依然可以再次利用,就好比一列火車,每節車廂只載了一半乘客,後面的路程中,可以繼續往裡面加入新的乘客。如下所示我們插入5000條記錄,你會發現頁的平均密度變化了,之前空閑的空間被重新利用了。
DECLARE @Index INT ;
SET @Index = 2;
WHILE @Index <= 10000
BEGIN
INSERT INTO dbo.space_test
SELECT @Index, REPLICATE(N'k', 4000);
SET @Index += 2;
END
GO