為什么有時SQL Server無法收縮數據庫文件


    首先要申明,一般情形下沒有必要對用戶數據庫的數據文件進行收縮,因為雖然可能看到有很多空間被占用,但是實際未釋放,但是當數據庫中有新的對象或者新的數據進來時,這些空間是會被重新使用到的。

    但是在某些特定情況下,比如磁盤空間快滿了,但是硬件小組暫時並未有足夠的資源可以調配,如果發現了該磁盤的某個數據庫中有大量的未使用空間,可能心想“可以搞定”。但是當實際收縮的時候,一直無法收縮,又涼涼了。

    那么這個時候,我們就要看下,為什么實際存在未使用空間,但是實際卻無法收縮。

 

    DBCC SHRINKFILE的工作原理:

DBCC SHRINKFILE執行時,是做的區(Extent)級別的動作。他會將使用過的區前移,沒有使用的區從文件中移除掉。但是,並不會將一個區中的空頁移除,然后合並區,也不會把頁面中的空間移除,合並頁面。所以如果一個數據庫中有很多的區,但是這些區中只有一兩個頁才有數據,那么DBCC SHRINKFILE就不會起作用。

    這也就解釋了上面所說的那些情況,為什么明明看到數據文件有空間,但是不能壓縮或者清空。通常的原因是數據文件里雖然有很多空的頁面,但是頁面是分布在各個區中,所以就沒辦法壓縮了。

    舉個例子:

use wisontest
go
create table show_extent
(a int,
 b nvarchar(3900))
 go
 declare @i int
 set @i=1
 while @i<=1000
 begin
	insert into show_extent values (1,replicate(N'a',3900))
	insert into show_extent values (2,replicate(N'b',3900))
	insert into show_extent values (3,replicate(N'c',3900))
	insert into show_extent values (4,replicate(N'd',3900))
	insert into show_extent values (5,replicate(N'e',3900))
	insert into show_extent values (6,replicate(N'f',3900))
	insert into show_extent values (7,replicate(N'g',3900))
	insert into show_extent values (8,replicate(N'h',3900))
	set @i=@i+1
end

dbcc showcontig('show_extent')

    這個時候得到如下的結果。可以看到申請了8000個數據頁,也就是1001個區。

DBCC SHOWCONTIG scanning 'show_extent' table...
Table: 'show_extent' (885578193); index ID: 0, database ID: 12
TABLE level scan performed.
- Pages Scanned................................: 8000
- Extents Scanned..............................: 1001
- Extent Switches..............................: 1000
- Avg. Pages per Extent........................: 8.0
- Scan Density [Best Count:Actual Count].......: 99.90% [1000:1001]
- Extent Scan Fragmentation ...................: 0.10%
- Avg. Bytes Free per Page.....................: 279.0
- Avg. Page Density (full).....................: 96.55%
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

    此時,我們刪除掉每個分區中的7個頁面,只保留a=5的記錄

delete show_extent where a<>5

exec sp_spaceused show_extent

exec sp_spaceused

  返回的結果如下,可以看到還是有一半的空間被占用到了(雖然實際上這個時候應該只使用1/8的空間才對)。

    

 

    如果此時,我們去執行DBCC SHRINKFILE,那么我們會發現沒有什么效果。面對這種情況的時候,我們可以通過對該表新建一個聚集索引來使得可以收縮文件(如果表有聚集索引,那么就是重建聚集索引)。 

create clustered index icx_show_extent on show_extent(a)
exec sp_spaceused show_extent
exec sp_spaceused

  

 

    此時就可看到未使用空間和理論值一樣了,如果此時需要做收縮文件的操作,那么就可以達到效果了。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM