• 为什么有时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
    

      

        此时就可看到未使用空间和理论值一样了,如果此时需要做收缩文件的操作,那么就可以达到效果了。 

  • 相关阅读:
    9.内存的了解
    8.时钟初始化
    3.2Linux的模块驱动
    3.1Linux内核的配置和编译
    5.10TCP客户端服务器
    5.9UDP客户端服务器-基于OK6410
    5.8fork父子进程
    4.NFC前台调度系统
    3.非标准的NDEF格式数据解析--IsoDep
    Android 布局学习之——LinearLayout属性baselineAligned的作用及baseline
  • 原文地址:https://www.cnblogs.com/Wison-Ho/p/14109612.html
Copyright © 2020-2023  润新知