SQL Server 如何在删除表后重用保留页

The*_*Guy 3 sql-server database-internals disk-space

我只是想知道:

  1. SQL Server 如何在删除 1GB 表后重用保留空间?(调用表T1)
  2. SQL Server 如何在截断表后重用保留空间?(称此表为 T2)

两者都是聚簇表(不是堆)。

Joh*_*ner 6

很简单,DROPorTRUNCATE语句将与该表相关联的任何已分配页(无论它是堆还是聚簇表)标记为不再分配,并且该空间被下一个需要额外空间的操作(例如新记录、页面拆分等)。

sys.allocation_units (Transact-SQL)

? 笔记

当您删除或重建大索引,或者删除或截断大表时,数据库引擎会推迟实际的页面释放及其关联的锁,直到事务提交之后。延迟删除操作不会立即释放分配的空间。因此,在删除或截断大对象后立即由 sys.allocation_units 返回的值可能无法反映实际可用的磁盘空间。

一个TRUNCATE TABLE操作是有效的同样的事情作为一个DROP TABLE声明,但它与重新创建已被删除后,立即表的奖金。这就是为什么TRUNCATE TABLE语句是数据定义语言 (DDL) 语句而不是数据操作语言语句(例如DELETE.

如果您想了解引擎如何释放和重用空间,您可以深入研究DBCC PAGE未记录的函数。Paul Randal 有几篇关于它的用法的文章(例如ref1ref2ref3ref4),如果您愿意,可以通读一下。

如果您有沙箱环境,您还可以运行以下一系列脚本,这些脚本将以相同的方式显示正在分配和释放的页面,无论是否执行aTRUNCATE TABLEDROP TABLE操作:

-- Create Test Database
USE [master]
GO

EXECUTE AS LOGIN = 'sa'

CREATE DATABASE [TestDB]

REVERT
GO

USE [TestDB]
GO

-- Look at GAM
DBCC PAGE(0, 1, 2, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
--Only 1016 pages are reserved.  This is because that's the initial size needed by data populating a "blank" database

ParentObject   Object                   Field                     VALUE
-------------- ------------------------ ------------------------- --------------
GAM: Header    GAM: Extent Alloc Status (1:0)        - (1:312)        ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:320)      - (1:1016)   NOT ALLOCATED 
*/

-- Look at SGAM
DBCC PAGE(0, 1, 3, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
The SGAM also shows only 1016 pages are reserved, this view will remain relatively unchanged throughout the demo

ParentObject  Object                     Field                    VALUE
------------- -------------------------- ------------------------ --------------
SGAM: Header  SGAM: Extent Alloc Status  (1:0)        - (1:304)   NOT ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:312)      -               ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:320)      - (1:1016)  NOT ALLOCATED 
*/

-- Create our Test Table
CREATE TABLE T1
(
    ID  INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
    Value   CHAR(8000)
)
GO

-- Populate it with exactly 1GB of data
INSERT INTO T1 (Value)
SELECT TOP 131072 ''
FROM sys.configurations t1
    CROSS JOIN sys.configurations t2
    CROSS JOIN sys.configurations t3
    CROSS JOIN sys.configurations t4


-- Table is 1GB in Size, as expected
EXEC sp_spaceused 'T1'

/*
name  rows    reserved    data        index_size  unused 
----- ------- ----------- ----------- ----------- -------
T1    131072  1052616 KB  1048576 KB  3904 KB     136 KB
*/

-- Recheck GAM and SGAM
-- Look at GAM
DBCC PAGE(0, 1, 2, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
This allocates 131072 8kb data-pages for the data and 488 8kb data-pages for the index
This view shows the location of the allocated and unallocated pages within the datafile

ParentObject   Object                   Field                     VALUE
-------------- ------------------------ ------------------------- --------------
GAM: Header    GAM: Extent Alloc Status (1:0)        - (1:8080)       ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:8088)     -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:8096)     - (1:16168)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:16176)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:16184)    - (1:24256)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:24264)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:24272)    - (1:32344)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:32352)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:32360)    - (1:40432)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:40440)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:40448)    - (1:48520)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:48528)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:48536)    - (1:56608)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:56616)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:56624)    - (1:64696)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:64704)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:64712)    - (1:72784)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:72792)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:72800)    - (1:80872)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:80880)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:80888)    - (1:88960)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:88968)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:88976)    - (1:97048)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:97056)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:97064)    - (1:105136)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:105144)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:105152)   - (1:113224)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:113232)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:113240)   - (1:121312)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:121320)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:121328)   - (1:129400)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:129408)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:129416)   - (1:130480)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:130488)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:130496)   - (1:132024)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:132032)   - (1:132088) NOT ALLOCATED
*/

-- Look at SGAM
DBCC PAGE(0, 1, 3, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
This view only changed to show no additional Shared Extents are allocated, though you can see 
the number of 8kb data-pages reserved in the db grew to 132,088

ParentObject  Object                     Field                      VALUE
------------- -------------------------- -------------------------- --------------
SGAM: Header  SGAM: Extent Alloc Status  (1:0)        - (1:304)     NOT ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:312)      -                 ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:320)      - (1:132088)  NOT ALLOCATED
*/


TRUNCATE TABLE T1

-- Let the background process mark the extents as NOT ALLOCATED, so wait 10 seconds before running this
-- Recheck GAM and SGAM
-- Look at GAM
DBCC PAGE(0, 1, 2, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
This shows that all pages that were previous used by T1 have been deallocated

ParentObject   Object                   Field                     VALUE
-------------- ------------------------ ------------------------- --------------
GAM: Header    GAM: Extent Alloc Status (1:0)        - (1:312)        ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:320)      - (1:132088) NOT ALLOCATED
*/


-- Look at SGAM
DBCC PAGE(0, 1, 3, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
No changes here, as the db didn't grow and we haven't done anything regarding mixed extents

ParentObject  Object                     Field                      VALUE
------------- -------------------------- -------------------------- --------------
SGAM: Header  SGAM: Extent Alloc Status  (1:0)        - (1:304)     NOT ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:312)      -                 ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:320)      - (1:132088)  NOT ALLOCATED
*/

-- Repopulate T1
INSERT INTO T1 (Value)
SELECT TOP 131072 ''
FROM sys.configurations t1
    CROSS JOIN sys.configurations t2
    CROSS JOIN sys.configurations t3
    CROSS JOIN sys.configurations t4

-- Table is 1GB in Size
EXEC sp_spaceused 'T1'

/*
name  rows    reserved    data        index_size  unused 
----- ------- ----------- ----------- ----------- -------
T1    131072  1052616 KB  1048576 KB  3904 KB     136 KB
*/

-- Recheck GAM and SGAM
-- Look at GAM
DBCC PAGE(0, 1, 2, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
Again, this allocates 131072 8kb data-pages for the data and 488 8kb data-pages for the index
This view shows the location of the allocated and unallocated pages within the datafile and they've
likely changed slightly from when they were first allocated, though the counts remain consistent

ParentObject   Object                   Field                     VALUE
-------------- ------------------------ ------------------------- --------------
GAM: Header    GAM: Extent Alloc Status (1:0)        - (1:8080)       ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:8088)     -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:8096)     - (1:16168)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:16176)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:16184)    - (1:24256)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:24264)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:24272)    - (1:32344)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:32352)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:32360)    - (1:40432)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:40440)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:40448)    - (1:48520)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:48528)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:48536)    - (1:56608)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:56616)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:56624)    - (1:64696)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:64704)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:64712)    - (1:72784)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:72792)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:72800)    - (1:80872)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:80880)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:80888)    - (1:88960)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:88968)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:88976)    - (1:97048)      ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:97056)    -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:97064)    - (1:105136)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:105144)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:105152)   - (1:113224)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:113232)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:113240)   - (1:121312)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:121320)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:121328)   - (1:129400)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:129408)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:129416)   - (1:130416)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:130424)   -            NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:130432)   - (1:131960)     ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:131968)   - (1:132024) NOT ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:132032)   - (1:132088)     ALLOCATED
*/

-- Look at SGAM
DBCC PAGE(0, 1, 3, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
Still no changes here, as the db didn't grow and we haven't done anything regarding mixed extents

ParentObject  Object                     Field                      VALUE
------------- -------------------------- -------------------------- --------------
SGAM: Header  SGAM: Extent Alloc Status  (1:0)        - (1:304)     NOT ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:312)      -                 ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:320)      - (1:132088)  NOT ALLOCATED
*/

DROP TABLE T1

-- Let the background process mark the extents as NOT ALLOCATED, so wait 10 seconds before running this
-- Recheck GAM and SGAM
-- Look at GAM
DBCC PAGE(0, 1, 2, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
Again, this shows that all pages that were previous used by T1 have been deallocated.
This is the same behavior we saw with a TRUNCATE, even though we just executed a DROP TABLE command.

ParentObject   Object                   Field                     VALUE
-------------- ------------------------ ------------------------- --------------
GAM: Header    GAM: Extent Alloc Status (1:0)        - (1:312)        ALLOCATED
GAM: Header    GAM: Extent Alloc Status (1:320)      - (1:132088) NOT ALLOCATED
*/


-- Look at SGAM
DBCC PAGE(0, 1, 3, 3) WITH TABLERESULTS, NO_INFOMSGS

/*
Still no changes here, as the db didn't grow and we haven't done anything regarding mixed extents

ParentObject  Object                     Field                      VALUE
------------- -------------------------- -------------------------- --------------
SGAM: Header  SGAM: Extent Alloc Status  (1:0)        - (1:304)     NOT ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:312)      -                 ALLOCATED
SGAM: Header  SGAM: Extent Alloc Status  (1:320)      - (1:132088)  NOT ALLOCATED
*/

-- Cleanup
USE [master]
GO

DROP DATABASE [TestDB]
GO
Run Code Online (Sandbox Code Playgroud)

有关 GAM、SGAM、范围和存储引擎基础知识的更多信息,请从Microsoft的页面和范围体系结构指南开始。希望这能回答你的问题,尽管我觉得你会有更多的问题要跟进。