包含LOB_Data列的表删除大量数据后表及数据库文件的收缩

最近有一张表(内含varchar(max)字段),占用空间达到240G,删除历史数据后几十万条后,空间并未得到释放。

然后用DBCC CLEANTABLE(0,tb_name,100)来释放删除记录后变长字段留下的空间,注意第三个参数为每个事务处理的行数,

强烈建议使用,默认是0,将整个操作作为一个事务处理!全程锁表!!

执行完DBCC CLEANTABLE后,发现表空间已经释放,占用空间几百兆,但此时还没完,我们数据库文件依然很大。

于是我们尝试用DBCC SHRINKFILE来收缩库文件,结果却出人意料,文件并没有收缩到我们预想的大小,而是远远大于所有表

的大小之和,100G之多,为什么?

我们通过DBCC SHOWFILESTATUS命令查看分区状态,发现有大量的未使用分区,于是开始怀疑是区内页填充密度过低导致的,

每个区8个页,如果有一个页不为空,SHRINKFILE命令也不会收缩该分区,因为SHRINKFILE命令是以区为单位的,它只会收缩掉

完全空的分区。

包含LOB_Data列的表删除大量数据后表及数据库文件的收缩

 

所以下面我们来看一下“肇事”表的填充密度到底如何,这里我们使用DBCC SHOWCONFIG(‘TB’)命令:

包含LOB_Data列的表删除大量数据后表及数据库文件的收缩

可以看到,虽然这张表的区的利用率比较低,为25.76%[34:132],即本来用34个分区就可以容纳的数据,它用了132个分区来容纳,

但是远远不可能造成上面199万个区的空间耗费!这到底是怎么回事!!

没错,bug再一次显了神威!相关KB:http://support.microsoft.com/kb/2967240/en-us

那么还有没有其它方法呢?答案是肯定的,那就是重建该对象:

方法1:重新一张结构一样的表,将原表数据导入新表,干掉原表,重命名新表;

方法2:将现有数据导出,TRUNCATE表,然后再将数据导回;

另外,经过测试,上面KB中提出的CU13 FOR SQL SERVER 2008 R2 SP2,安装之后并不能使DBCC SHRINKFILE生效,故应该为避免以上情景的出现!

包含LOB_Data列的表删除大量数据后表及数据库文件的收缩

上一篇:9月18日,SQL学习基础1


下一篇:谈MongoDB读取连接超时的异常