适用于:SQL Server
Azure SQL 数据库
Azure SQL 托管实例
Azure Synapse Analytics
Microsoft Fabric 中的 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 ]
参数
{ database_name | database_id |0 }
数据库的名称或ID可以缩小。 值为0表示当前数据库。
target_percent
缩小操作完成后数据库文件中剩余的空间百分比。
如果你指定 target_percent ,则 TRUNCATEONLY缩小操作可能不会释放文件末尾的空闲空间。
NOTRUNCATE
将分配的页面从文件的末尾移动到文件前面的未分配页面。 此操作会压缩文件中的数据。 target_percent 为可选。 Azure Synapse Analytics 不支持此选项。
文件末尾的可用空间不会返回给操作系统,并且文件的物理大小也不会更改。 因此,指定 NOTRUNCATE 时,数据库似乎不会收缩。
NOTRUNCATE 仅适用于数据文件。
NOTRUNCATE 不影响日志文件。
TRUNCATEONLY
将文件末尾的所有可用空间释放给操作系统。 不移动文件内的任何页面。 数据文件仅收缩到最后指定的盘区。 Azure Synapse Analytics 不支持此选项。
如果你指定 target_percent ,则 TRUNCATEONLY缩小操作可能不会释放文件末尾的空闲空间。
使用 NO_INFOMSGS
取消严重级别从 0 到 10 的所有信息性消息。
收缩操作的 WAIT_AT_LOW_PRIORITY
适用于:SQL Server 2022 (16.x) 及以后版本,Azure SQL 数据库,Azure SQL 托管实例,Microsoft Fabric 中的 SQL 数据库
低优先级等待功能减少了缩小操作中的锁争用。 有关详细信息,请参阅了解 DBCC SHRINKDATABASE 的并发问题。
此功能与联机索引操作的 WAIT_AT_LOW_PRIORITY 类似,但有一些差异。
- 你不能指定
ABORT_AFTER_WAIT选项NONE。 - 你不能设置这个
MAX_DURATION选项。 收缩操作的低优先级锁定超时总是一分钟。
WAIT_AT_LOW_PRIORITY
当在模式下WAIT_AT_LOW_PRIORITY执行缩小命令时,需要对索引分配映射(IAM)页面设置模式稳定性(Sch-S)锁的查询不会被缩小操作阻挡。 然而,缩小操作可以通过 IAM 页面上的锁来阻止 Sch-S 。 只有当它能够获得所需的 IAM 页面的 schema 修改锁(Sch-M)时,Shrink 才会继续执行。
如果在模式下的缩小操作 WAIT_AT_LOW_PRIORITY 无法获得该锁,因为长期查询持有锁 Sch-S ,缩小操作会以错误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。
{ ABORT_AFTER_WAIT = [ 自言 |阻挡者] }
SELFSELF是默认选项。 退出当前正在执行的缩小数据库操作,不采取任何后续操作。BLOCKERS终止阻塞收缩文件操作的所有用户事务,使操作可继续进行。 该
BLOCKERS选项需要登录用户拥有ALTER ANY CONNECTIONORKILL DATABASE CONNECTION权限。
结果集
下表对结果集中的列进行了说明。
| 列名称 | 说明 |
|---|---|
DbId |
数据库引擎试图收缩的文件的数据库标识号。 |
FileId |
数据库引擎尝试收缩的文件的文件标识号。 |
CurrentSize |
文件当前占用的 8 KB 页数。 |
MinimumSize |
文件最低可以占用的 8 KB 页数。 此值与文件的最小大小或最初创建时的大小相对应。 |
UsedPages |
文件当前使用的 8 KB 页数。 |
EstimatedPages |
数据库引擎估计文件能够收缩到的 8 KB 页数。 |
注意
数据库引擎不会显示未压缩的文件行。
注解
若要收缩特定数据库的所有数据和日志文件,请执行 DBCC SHRINKDATABASE 命令。 若要一次收缩一个特定数据库中的一个数据或日志文件,请执行 DBCC SHRINKFILE 命令。
若要查看数据库中当前的可用(未分配)空间量,请运行 sp_spaceused。
可在进程中的任一点停止 DBCC SHRINKDATABASE 操作,任何已完成的工作都将保留。
数据库不能小于配置的数据库最小大小。 在最初创建数据库时指定最小大小。 或者,最小大小可以是使用文件大小更改操作显式设置的最后大小。
DBCC SHRINKFILE 或 ALTER DATABASE 等操作是文件大小更改操作的示例。
假设最初创建的数据库大小为 10 MB。 然后,它增长到 100 MB。 即使数据库中的所有数据都已删除,数据库可以减少到的最小大小也为 10 MB。
你可以在运行DBCC SHRINKDATABASE时指定NOTRUNCATE选项或选项。TRUNCATEONLY 如果不指定任何选项,结果与先运行 和 NOTRUNCATE 再运行 DBCC SHRINKDATABASEDBCC SHRINKDATABASE 的TRUNCATEONLY操作相同。
收缩数据库不必处于单用户模式。 其他用户可以在数据库收缩时在其中工作,包括系统数据库。
备份数据库时,无法收缩数据库。 反之,也不能在数据库执行收缩操作时备份数据库。
在 Azure Synapse 的 SQL 池中,避免运行 shrink 命令,因为这是 I/O 密集操作,可能会使专用 SQL 池(前称 SQL DW)离线。 该命令还会影响数据仓库快照的成本。
已知问题
适用于:SQL Server、Azure SQL 数据库、Azure SQL 托管实例、Azure Synapse Analytics 专用 SQL 池
- 在 SQL Server 2022(16.x)及更早版本中,压缩列存储段中 LOB 列类型(varbinary(max)、varchar(max)和 nvarchar(max))所使用的页面不能通过
DBCC SHRINKDATABASE和DBCC SHRINKFILE移动。 有关详细信息,请参阅 列存储索引中的新增功能。
DBCC SHRINKDATABASE 的工作原理
DBCC SHRINKDATABASE 以每个文件为单位对数据文件进行收缩。然而,在对日志文件进行收缩时,它将视为所有的日志文件都存在于一个连续的日志池中。 文件始终从末尾开始收缩。
假设你有一个数据库中的两个日志文件和一个数据文件,名为 mydb。 数据文件和日志文件分别是 10 MB,并且数据文件包含 6 MB 数据。 数据库引擎 计算每个文件的目标大小。 这个值是缩小后文件的目标大小。 当你用target_percent指定DBCC SHRINKDATABASE时,数据库引擎计算目标大小为缩小后文件中target_percent的空闲空间。
例如,如果为收缩 将 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 环境中。
例如,用户查询可能会在索引分配映射(IAM)页面上获得模式稳定性Sch-S()锁,并保持该锁直到完成。 在常规使用时尝试回收空间时,缩小数据库和缩小文件操作在移动或删除IAM页面时需要模式修改Sch-M锁,从而阻止 Sch-S 用户查询所需的锁。 因此,长时间运行的查询可能会阻碍缩小操作。 这种行为也意味着任何需要在IAM页面上锁定 Sch-S 的新查询都可能排在压缩操作之后,进一步加剧了并发问题。
在 SQL Server 2022(16.x)中引入的低优先级等待功能,通过在该模式中对 IAM 页面WAIT_AT_LOW_PRIORITY施加模式修改锁来解决这一问题。 有关详细信息,请参阅收缩操作的 WAIT_AT_LOW_PRIORITY。
有关Sch-SSch-M锁的更多信息,请参见事务锁定与行版本控制指南。
最佳实践
当您计划收缩数据库时,请考虑以下信息:
在执行会产生未使用空间的操作(如截断表或删除表操作)后,执行收缩操作最有效。
大多数数据库需要一些空闲空间来进行日常操作。 如果你反复缩小数据库文件,发现数据库大小再次增长,说明常规操作需要空闲空间。 在这种情况下,反复缩小数据库文件反而适得其反。 文件在缩小后分配新空间所需的文件增长可能会影响性能。
收缩操作无法保留数据库中索引的碎片状态,且可能增加索引碎片,从而降低使用大型扫描查询时的读取I/O吞吐量。
除非有特定的要求,否则不要将
AUTO_SHRINK数据库选项设置为ON。如果你需要缩小大型数据库的数据文件,可以考虑使用 ShrinkDriver PowerShell 脚本。 该脚本自动化并简化了缩小过程,使其成为单一、可观察且可恢复的操作。 脚本会并行缩减多个文件,中断时重试,并在运行过程中输出详细的状态报告。
疑难解答
在基于行版本控制的隔离级别下运行的事务可能会阻止收缩操作。 例如,你在运行一个基于行版本控制隔离层的大型删除操作时。DBCC SHRINKDATABASE 在这种情况下,缩小操作会等待删除操作完成后才对文件进行收缩。 收缩操作等待时,DBCC SHRINKFILE 和 DBCC 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 的快照交易会阻挡缩小操作。 该事务是收缩操作完成的最后一个事务。 它还表示transaction_sequence_numsys.dm_tran_active_snapshot_database_transactions动态管理视图中的 or first_snapshot_sequence_num 列包含 15 的值。 该视图中的 transaction_sequence_num 或 first_snapshot_sequence_num 列可能包含小于收缩操作完成的最后一个事务 (109) 的数字。 如果是这样,收缩操作将等待这些事务完成。
要解决这个问题,你可以采取以下其中之一:
- 终止阻止收缩操作的事务。
- 终止收缩操作。 所有已完成的工作都会保留。
- 不执行任何操作,并允许收缩操作等到阻塞事务完成。
权限
要求具有 sysadmin 固定服务器角色或 db_owner 固定数据库角色的成员身份。
示例
本文中的代码示例使用 AdventureWorks2025 或 AdventureWorksDW2025 示例数据库,可以从 Microsoft SQL Server 示例和社区项目 主页下载该数据库。
答: 收缩数据库并指定可用空间的百分比
以下示例将减小 UserDB 用户数据库中数据文件和日志文件的大小,以便在数据库中留出 10% 的可用空间。
DBCC SHRINKDATABASE (UserDB, 10);
GO
B. 截断数据库
以下示例将 AdventureWorks2025 示例数据库中的数据和日志文件收缩到最后指定的盘区。
DBCC SHRINKDATABASE (AdventureWorks2025, TRUNCATEONLY);
C. 收缩 Azure Synapse Analytics 数据库
DBCC SHRINKDATABASE (database_A);
DBCC SHRINKDATABASE (database_B, 10);
D. 压缩数据库 WAIT_AT_LOW_PRIORITY
以下示例尝试减小 AdventureWorks2025 数据库中数据文件和日志文件的大小,以便在数据库中留出 20% 的可用空间。 如果在一分钟内无法获取锁,收缩操作将中止。
DBCC SHRINKDATABASE ([AdventureWorks2025], 20) WITH WAIT_AT_LOW_PRIORITY (ABORT_AFTER_WAIT = SELF);