SQL Server存储空间的分配和回收

数据库中的数据文件空间主要用来存放表和索引的数据,区是分配存储空间的单位。

SQL Server分配存储空间的方式

SQL Server每个区的大小固定为64KB。我们知道区由混合区和统一区两类。表或索引的前8个数据页都在混合区中分配,当其空间超过8个数据页时,就开始给其分配统一区。
  SQL Server不会对新创建的空表分配区,分配区的东西会延迟到对表添加数据的时候。我们可以新建一个空表并用dbcc extentinfo命令查看新表被分配的区的情况,可以发现执行结果为空。

SQL Server表数据在多个数据文件上的分布

因为dbcc extentinfo命令不能显示extent的编号,所以不能像Oracle中查询dba_extents一样,可以根据extent_id得到各个extent分配的先后顺序。
  对于文件组中的空间分配,联机丛书有以下说明:文件组对组内的所有文件都使用按比例填充策略。将数据写入文件组时,数据库引擎会根据文件中的可用空间量将一定比例的数据写入文件组中的每个文件,而不是将所有数据先写满第一个文件,然后再写入下一个文件。例如,如果文件f1有100MB可用空间,文件f2有200MB可用空间,则从文件f1中分配一个区,从文件f2中分配两个区,以此类推。这样,两个文件几乎同时填满,并且可获得简单的条带化。
  只要文件组中的所有文件满了,数据库引擎就自动按照循环方式一次扩展一个文件,以容纳更多数据(假定数据文件设置为自动增长)。例如,某个文件组由3个文件组成,它们都设置为自动增长。当文件组中所有文件的空间都已用完时,只扩展第一个文件。当第一个文件已满,无法再向文件组中写入更多数据时,将扩展第二个文件。当第二个文件已满,无法再向文件组中写入更多数据时,将扩展第三个文件。第三个文件已满,无法再向文件组中写入更多数据时,将再次扩展第一个文件,以此类推。

delete及truncate操作对表占用存储空间的影响

1.delete情形
  创建测试表t并向表t增加100条记录,然后查看表被分配的区的情况:

create table t(a int,b char(100))
go
-- 向表t增加100条记录
declare @i int
set @i = 1
while @i<101
begin
   insert into t values(@i,'x')
   set @i = @i+1
end
go
-- 查看表被分配的区的情况
dbcc extentinfo(DBForTest,t)
go

file_id     page_id     pg_alloc    ext_size    object_id   index_id    
----------- ----------- ----------- ----------- ----------- ----------- 
          1          90           1           1  2121058592           0
          1          94           1           1  2121058592           0

使用不附带where条件的delete命令清空表中的记录:

delete from t
go

然后重新查询表被分配的区的情况,可以发现查询结果未发生变化,即删除记录占用的空间未释放:

dbcc extentinfo(DBForTest,t)
go

file_id     page_id     pg_alloc    ext_size    object_id   index_id    
----------- ----------- ----------- ----------- ----------- ----------- 
          1          90           1           1  2121058592           0
          1          94           1           1  2121058592           0

再重新执行上面添加记录的命令,然后执行dbcc extentinfo命令查询t表空间的变化:

declare @i int
set @i = 1
while @i<101
begin
   insert into t values(@i,'x')
   set @i = @i+1
end
go

查询表t上区的情况:

dbcc extentinfo(DBForTest,t)
go

file_id     page_id     pg_alloc    ext_size    object_id   index_id    
----------- ----------- ----------- ----------- ----------- ----------- 
          1          90           1           1  2121058592           0
          1          94           1           1  2121058592           0

显然,新增加的记录并未导致新空间的分配,而是重用了原来的空间。

2.truncate的情形
  下面对t表执行truncate操作:

truncate table t

然后再查询其空间变化:

dbcc extentinfo(DBForTest,t)
go

查询结果为空,显然,t表所占用的空间都被释放了。

    原文作者:zoyoto
    原文地址: https://www.jianshu.com/p/852d4882c0dd
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞