DBCC SHRINKDATABASE (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse Analytics

收缩指定数据库中的数据文件和日志文件的大小。

Transact-SQL 语法约定

语法

SQL Server 的语法:

DBCC SHRINKDATABASE   
( database_name | database_id | 0   
     [ , target_percent ]   
     [ , { NOTRUNCATE | TRUNCATEONLY } ]   
)  
[ WITH 

    {     
         [ WAIT_AT_LOW_PRIORITY 
            [ ( 
                  <wait_at_low_priority_option_list>
             )] 
         ] 
         
         [ , NO_INFOMSGS]
    }
]

< wait_at_low_priority_option_list > ::=  
    <wait_at_low_priority_option>
    | <wait_at_low_priority_option_list> , <wait_at_low_priority_option>

< wait_at_low_priority_option > ::=
  ABORT_AFTER_WAIT = { SELF | BLOCKERS }

Azure Synapse Analytics 的语法:

DBCC SHRINKDATABASE
( database_name
     [ , target_percent ]
)
[ WITH NO_INFOMSGS ]

注意

若要查看 SQL Server 2014 及更早版本的 Transact-SQL 语法,请参阅早期版本文档

参数

database_name | database_id | 0

要收缩的数据库名称或 ID。 0 指定使用当前数据库。

target_percent

数据库收缩后的数据库文件中所需的剩余可用空间百分比。

NOTRUNCATE

将分配的页面从文件的末尾移动到文件前面的未分配页面。 此操作会压缩文件中的数据。 target_percent 为可选。 Azure Synapse Analytics 不支持此选项。

文件末尾的可用空间不会返回给操作系统,并且文件的物理大小也不会更改。 因此,指定 NOTRUNCATE 时,数据库似乎不会收缩。

NOTRUNCATE 只适用于数据文件。 NOTRUNCATE 不影响日志文件。

TRUNCATEONLY

将文件末尾的所有可用空间释放给操作系统。 不移动文件内的任何页面。 数据文件仅收缩到最后指定的盘区。 如果使用 TRUNCATEONLY 指定,则会忽略 target_percent。 Azure Synapse Analytics 不支持此选项。

使用 TRUNCATEONLY 选项的 DBCC SHRINKDATABASE 仅影响数据库事务日志文件。 要截断数据文件,请改用 DBCC SHRINKFILE。 有关详细信息,请参阅 DBCC SHRINKFILE

WITH NO_INFOMSGS

取消严重级别从 0 到 10 的所有信息性消息。

收缩操作的 WAIT_AT_LOW_PRIORITY

适用于:SQL Server 2022 (16.x) 及更高版本、Azure SQL 数据库和 Azure SQL 托管实例

低优先级等待功能减少了锁争用。 有关详细信息,请参阅了解 DBCC SHRINKDATABASE 的并发问题

此功能与联机索引操作的 WAIT_AT_LOW_PRIORITY 类似,但有一些差异。

  • 无法指定 ABORT_AFTER_WAIT 选项“无”。

WAIT_AT_LOW_PRIORITY

WAIT_AT_LOW_PRIORITY 模式下执行收缩命令时,在收缩操作停止等待并开始执行之前,等待收缩操作不会阻止需要架构稳定性 (Sch-S) 锁的新查询。 收缩操作将在其能够获取架构修改 (Sch-M) 锁时执行。 在 WAIT_AT_LOW_PRIORITY 模式下,如果新的收缩操作由于长时间运行的查询而无法获取锁,则收缩操作最终会在 1 分钟(默认)后超时,并且会退出而不会出错。

WAIT_AT_LOW_PRIORITY 模式下,如果新的收缩操作由于长时间运行的查询而无法获取锁,则收缩操作最终会在 1 分钟(默认)后超时,并且会退出而不会出错。 如果由于并发查询或持有 Sch-S 锁的查询导致收缩操作而无法获取 Sch-M 锁,就会出现这种情况。 如果发生超时,系统将向 SQL Server 错误日志发送错误 49516 消息,例如:Msg 49516, Level 16, State 1, Line 134 Shrink timeout waiting to acquire schema modify lock in WLP mode to process IAM pageID 1:2865 on database ID 5。 此时,只需在 WAIT_AT_LOW_PRIORITY 模式下重试收缩操作,因为已知应用程序不会受到影响。

ABORT_AFTER_WAIT = [ SELF | BLOCKERS ]

  • SELF

    SELF 是默认选项。 不采取任何操作,直接退出当前执行的收缩数据库操作。

  • BLOCKERS

    终止阻塞收缩数据库操作的所有用户事务,使操作可继续进行。 BLOCKERS 选项需要登录名具有 ALTER ANY CONNECTION 权限。

结果集

下表对结果集中的列进行了说明。

列名称 说明
DbId 数据库引擎试图收缩的文件的数据库标识号。
FileId 数据库引擎尝试收缩的文件的文件标识号。
CurrentSize 文件当前占用的 8 KB 页数。
MinimumSize 文件最低可以占用的 8 KB 页数。 此值与文件的最小大小或最初创建时的大小相对应。
UsedPages 文件当前使用的 8 KB 页数。
EstimatedPages 数据库引擎估计文件能够收缩到的 8 KB 页数。

注意

数据库引擎不显示未收缩的文件的行。

备注

注意

在 Azure Synapse 中,建议不要运行收缩命令,因为这是 I/O 密集型操作,并且会使专用 SQL 池(以前称为 SQL DW)脱机。 此外,运行此命令后,还会对数据仓库快照产生成本影响。

若要收缩特定数据库的所有数据和日志文件,请执行 DBCC SHRINKDATABASE 命令。 若要一次收缩一个特定数据库中的一个数据或日志文件,请执行 DBCC SHRINKFILE 命令。

若要查看数据库中当前的可用(未分配)空间量,请运行 sp_spaceused

可在进程中的任一点停止 DBCC SHRINKDATABASE 操作,任何已完成的工作都将保留。

数据库不能小于配置的数据库最小大小。 在最初创建数据库时指定最小大小。 或者,最小大小可以是使用文件大小更改操作显式设置的最后大小。 DBCC SHRINKFILEALTER DATABASE 等操作是文件大小更改操作的示例。

假设最初创建的数据库大小为 10 MB。 然后,它增长到 100 MB。 即使数据库中的所有数据都已删除,数据库可以减少到的最小大小也为 10 MB。

运行 DBCC SHRINKDATABASE 时指定 NOTRUNCATE 选项或 TRUNCATEONLY 选项。 如果未指定,则结果与使用 NOTRUNCATE 运行 DBCC SHRINKDATABASE 操作然后使用 TRUNCATEONLY 运行 DBCC SHRINKDATABASE 操作的结果相同。

收缩数据库不必处于单用户模式。 其他用户可以在数据库收缩时在其中工作,包括系统数据库。

备份数据库时,无法收缩数据库。 反之,也不能在数据库执行收缩操作时备份数据库。

使用 WAIT_AT_LOW_PRIORITY 指定时,收缩操作的 Sch-M 锁定请求将在执行命令 1 分钟时按低优先级等待。 如果在此期间,操作被阻止,将执行指定的 ABORT_AFTER_WAIT 操作。

DBCC SHRINKDATABASE 的工作原理

DBCC SHRINKDATABASE 以每个文件为单位对数据文件进行收缩。然而,在对日志文件进行收缩时,它将视为所有的日志文件都存在于一个连续的日志池中。 文件始终从末尾开始收缩。

假设拥有几个日志文件、一个数据文件和一个名为 mydb 的数据库。 数据文件和日志文件分别是 10 MB,并且数据文件包含 6 MB 数据。 数据库引擎 计算每个文件的目标大小。 此值是文件要收缩到的大小。 如果使用 target_percent 指定 DBCC SHRINKDATABASE,则数据库引擎计算得出的目标大小为收缩后文件中可用空间的 target_percent 数量。

例如,如果为收缩 mydb 将 target_percent 指定为 25,则数据库引擎计算得出此文件的目标大小为 8 MB(6 MB 数据加上 2 MB 可用空间)。 因此,数据库引擎 将数据文件后 2 MB 中的所有数据移动到数据文件前 8 MB 的任何可用空间中,然后对该文件进行收缩。

假设 mydb 的数据文件包含 7 MB 的数据。 将 target_percent 指定为 30,以允许将此数据文件收缩到可用空间的 30%。 但是,将 target_percent 指定为 40 不会收缩数据文件,因为无法在数据文件的当前总大小中创建足够的可用空间。

可以用另一种方法来思考此问题:40% 的所要求可用空间加上 70% 的整个数据文件大小(10 MB 中的 7 MB)超过了 100%。 任何大于 30 的 target_percent 都不会收缩数据文件。 它不会收缩是因为所需的可用百分比加上数据文件当前占用的百分比大于 100%。

对于日志文件,数据库引擎使用 target_percent 计算整个日志的目标大小。 这就是为什么 target_percent 是收缩操作后日志中的可用空间量的原因。 之后,整个日志的目标大小转换为每个日志文件的目标大小。

DBCC SHRINKDATABASE 尝试立即将每个物理日志文件收缩到其目标大小。 假设逻辑日志没有任何部分位于超出日志文件目标大小的虚拟日志中。 然后文件成功截断,DBCC SHRINKDATABASE 完成且没有生成任何消息。 但是,如果部分逻辑日志位于超出目标大小的虚拟日志中,则 数据库引擎 将释放尽可能多的空间,并发出一条信息性消息。 该消息说明需要执行哪些操作来将逻辑日志移出位于文件末尾的虚拟日志。 运行操作后,DBCC SHRINKDATABASE 可用于释放剩余空间。

日志文件只能收缩到虚拟日志文件边界。 这就是为什么不可能将日志文件收缩到小于虚拟日志文件大小的原因。 即使未在使用它也可能无法实现。 虚拟日志文件的大小在创建或扩展这些日志文件时由数据库引擎动态选择。

了解 DBCC SHRINKDATABASE 的并发问题

收缩数据库和收缩文件命令可能会导致并发问题,尤其是在主动维护(例如重新生成索引)时或繁忙的 OLTP 环境中。 当应用程序对数据库表执行查询时,这些查询将获取和维护架构稳定性锁 (Sch-S),直到查询完成其操作。 尝试在常规使用期间回收空间时,收缩数据库和收缩文件操作当前需要在移动或删除索引分配映射 (IAM) 页时使用架构修改锁 (Sch-M),从而阻止用户查询所需的 Sch-S 锁。 因此,长时间运行的查询将阻止收缩操作,直到查询完成。 这意味着任何需要 Sch-S 锁的新查询也都会在等待收缩操作之后排队,并且也会被阻止,这进一步加剧了这种并发问题。 这可能会严重影响应用程序查询性能,也会对完成必要的维护以收缩数据库文件造成困难。 SQL Server 2022 (16.x) 中引入了收缩低优先级等待 (WLP) 功能,通过在 WAIT_AT_LOW_PRIORITY 模式下获取架构修改锁解决了这个问题。 有关详细信息,请参阅收缩操作的 WAIT_AT_LOW_PRIORITY

有关 Sch-S 和 Sch-M 锁的详细信息,请参阅事务锁定和行版本控制指南

最佳实践

当您计划收缩数据库时,请考虑以下信息:

  • 在执行会产生未使用空间的操作(如截断表或删除表操作)后,执行收缩操作最有效。
  • 大多数数据库都需要一些可用空间,以供常规日常操作使用。 如果反复收缩数据库文件并注意到数据库大小再次变大,则表明常规操作需要可用空间。 在这种情况下,反复收缩数据库文件是一种无谓的操作。 增长数据库文件所需的自动增长事件会影响性能。
  • 收缩操作不保留数据库中索引的碎片状态,通常还会在一定程度上增加碎片。 此结果是不要反复收缩数据库的另一个原因。
  • 除非有特定要求,否则不要将 AUTO_SHRINK 数据库选项设置为 ON。

疑难解答

收缩操作可能会被在基于行版本控制的隔离级别下运行的事务阻止。 例如,在执行 DBCC SHRINKDATABASE 操作时,正在基于行版本控制的隔离级别下运行大型删除操作。 当这种情况发生时,收缩操作会等到删除操作完成后再收缩文件。 收缩操作等待时,DBCC SHRINKFILEDBCC SHRINKDATABASE 操作会打印一条提示消息(5202 表示 SHRINKDATABASE,5203 表示 SHRINKFILE)。 此消息在第一个小时内每五分钟打印到 SQL Server 错误日志一次,然后在后续每个小时打印一次。 例如,如果错误日志包含以下错误消息:

DBCC SHRINKDATABASE for database ID 9 is waiting for the snapshot
transaction with timestamp 15 and other snapshot transactions linked to
timestamp 15 or with timestamps older than 109 to finish.

此错误表示时间戳早于 109 的快照事务将阻止收缩操作。 该事务是收缩操作完成的最后一个事务。 它还说明 sys.dm_tran_active_snapshot_database_transactions (Transact-SQL) 动态管理视图中的 transaction_sequence_numfirst_snapshot_sequence_num 列包含值 15。 该视图中的 transaction_sequence_numfirst_snapshot_sequence_num 列可能包含小于收缩操作完成的最后一个事务 (109) 的数字。 如果是这样,收缩操作将等待这些事务完成。

若要解决此问题,请执行下列任务之一:

  • 终止阻止收缩操作的事务。
  • 终止收缩操作。 所有已完成的工作都会保留。
  • 不执行任何操作,并允许收缩操作等到阻塞事务完成。

权限

要求具有 sysadmin 固定服务器角色或 db_owner 固定数据库角色的成员身份。

示例

A. 收缩数据库并指定可用空间的百分比

以下示例将减小 UserDB 用户数据库中数据文件和日志文件的大小,以便在数据库中留出 10% 的可用空间。

DBCC SHRINKDATABASE (UserDB, 10);
GO

B. 截断数据库

以下示例将 AdventureWorks2022 示例数据库中的数据和日志文件收缩到最后指定的盘区。

DBCC SHRINKDATABASE (AdventureWorks2022, TRUNCATEONLY);

C. 收缩 Azure Synapse Analytics 数据库

DBCC SHRINKDATABASE (database_A);
DBCC SHRINKDATABASE (database_B, 10);

D. 使用 WAIT_AT_LOW_PRIORITY 收缩数据库

以下示例尝试减小 AdventureWorks2022 数据库中数据文件和日志文件的大小,以便在数据库中留出 20% 的可用空间。 如果无法在一分钟内获取锁,收缩操作将中止。

DBCC SHRINKDATABASE ([AdventureWorks2022], 20) WITH WAIT_AT_LOW_PRIORITY (ABORT_AFTER_WAIT = SELF);

另请参阅

后续步骤