很多時候,我們經常使用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