适用于:SQL Server
Azure SQL 数据库
Azure SQL 托管实例
Microsoft Fabric 中的 SQL 数据库
收缩当前数据库的指定数据或日志文件大小。 可以使用它将一个文件中的数据移到同一文件组中的其他文件,这会清空文件,从而允许删除数据库。 可以将文件收缩到小于创建大小,同时将最小文件大小重置为新值。
仅在必要时使用 DBCC SHRINKFILE ,因为收缩是一个长期且资源密集的操作。
注意
不要把收缩手术当作常规维护。 由于常规、定期的业务操作而增长的数据和日志文件不需要收缩操作。
语法
DBCC SHRINKFILE
(
{ file_name | file_id }
{ [ , EMPTYFILE ]
| [ [ , target_size ] [ , { 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 }
参数
file_name
文件的逻辑名称是要缩小的。
file_id
文件的识别码(ID)可以缩小。 若要获取文件 ID,请使用 FILE_IDEX 系统函数,或查询当前数据库中的 sys.database_files 目录视图。
target_size
整数,表示文件的新大小(以 MB 为单位)。 如果你设置target_size0或不指定,文件DBCC SHRINKFILE会被缩小到创建大小。
可以使用 DBCC SHRINKFILE <target_size> 缩小空文件的默认大小。 例如,如果创建一个 5 MB 的文件,然后在文件仍然为空的时候将文件收缩为 3 MB,默认文件大小将设置为 3 MB。 这只适用于永远不会包含数据的空文件。
FILESTREAM 文件组容器不支持此选项。
如果 target_size 已指定,DBCC SHRINKFILE 会尝试将文件收缩到目标大小。 要释放的文件区域中的已用页移到文件保留区域中的可用空间。 例如,对于 10 MB 数据文件,target_size 为 DBCC SHRINKFILE 的 8 操作会将文件最后 2 MB 中的所有已用页移到文件前 8 MB 中的任何未分配页中。
DBCC SHRINKFILE 不会收缩已超过所需存储数据大小的文件。 例如,如果使用 10 MB 数据文件中的 7 MB,则带有 target_size 为 6 的 DBCC SHRINKFILE 语句只能将该文件收缩到 7 MB,而不能收缩到 6 MB。
如果你指定target_size,TRUNCATEONLYDBCC SHRINKFILE文件末尾可能不会释放空闲空间。
EMPTYFILE 文件
将指定文件中的所有数据迁移到同一文件组中的其他文件。 也就是说,EMPTYFILE 将指定文件中的数据迁移到同一文件组中的其他文件。
EMPTYFILE 确保不会将任何新数据添加到文件中(尽管此文件不是只读文件)。 你可以用这个 ALTER DATABASE 语句来删除文件。 如果你用该 ALTER DATABASE 语句更改文件大小,只读标志会被重置,数据可以添加。
对于 FILESTREAM 文件组容器,无法使用 ALTER DATABASE 删除文件,除非 FILESTREAM 垃圾回收器已运行,并删除了 EMPTYFILE 已复制到另一个容器的所有不必要文件组容器文件。 有关详细信息,请参阅 sp_filestream_force_garbage_collection。 有关移除 FILESTREAM 容器的信息,请参见文件与文件组选项中的ALTER DATABASE相应部分
EMPTYFILE不支持Azure SQL 数据库、Azure SQL 数据库 Hyperscale或Microsoft Fabric中的SQL数据库。
NOTRUNCATE
无论是否指定 target_percent,将数据文件末尾中的已分配页移到文件开头的未分配页区域中。 操作系统不会回收文件末尾的可用空间,文件的物理大小也不会改变。 因此,如果指定 NOTRUNCATE,文件看起来就像没有收缩一样。
NOTRUNCATE 只适用于数据文件。 日志文件不受影响。
FILESTREAM 文件组容器不支持此选项。
TRUNCATEONLY
将文件末尾的所有可用空间释放给操作系统,但不在文件内部移动任何页。 数据文件只收缩到最后分配的区。
如果指定TRUNCATEONLY,则可能不会释放文件末尾的可用空间。
该 TRUNCATEONLY 选项不会移动日志中的信息,但会移除日志文件末尾的非活跃虚拟日志文件(VLF)。 FILESTREAM 文件组容器不支持此选项。
使用 NO_INFOMSGS
取消显示所有信息性消息。
收缩操作的 WAIT_AT_LOW_PRIORITY
适用于:SQL Server 2022 (16.x) 及以后版本,Azure SQL 数据库,Azure SQL 托管实例,Microsoft Fabric 中的 SQL 数据库
低优先级等待功能减少了缩小操作中的锁争用。 更多信息请参见 《理解DBCC SHRINKFILE的并发问题》。
此功能与联机索引操作的 WAIT_AT_LOW_PRIORITY 类似,但有一些差异。
- 你不能指定选项
NONE。ABORT_AFTER_WAIT - 你不能设置这个
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 = [ 自言 |阻挡者] }
适用于:SQL Server(SQL Server 2022(16.x)及以后版本)、Azure SQL 数据库、Microsoft Fabric 中的 SQL 数据库。
SELFSELF是默认选项。 退出当前正在执行的缩小文件操作,无需采取任何后续操作。BLOCKERS终止阻塞收缩文件操作的所有用户事务,使操作可继续进行。 该
BLOCKERS选项需要登录用户拥有ALTER ANY CONNECTIONORKILL DATABASE CONNECTION权限。
结果集
下表描述了结果集列。
| 列名称 | 说明 |
|---|---|
DbId |
数据库引擎试图收缩的文件的数据库标识号。 |
FileId |
数据库引擎试图收缩的文件的文件标识号。 |
CurrentSize |
文件当前占用的 8 KB 页数。 |
MinimumSize |
文件最低可以占用的 8 KB 页数。 此数字对应于文件的大小下限或最初创建大小。 |
UsedPages |
文件当前使用的 8 KB 页数。 |
EstimatedPages |
数据库引擎估计文件能够收缩到的 8 KB 页数。 |
备注
DBCC SHRINKFILE 适用于当前数据库的文件。 有关如何更改当前数据库的更多信息,请参见 USE。
可以随时停止执行 DBCC SHRINKFILE 操作,并保留任何已完成的工作。 如果你使用 EMPTYFILE 参数并取消操作,文件不会被标记,以防添加其他数据。
其他用户可以在文件收缩期间使用数据库,数据库不必处于单用户模式。 无需在单用户模式下运行 SQL Server 实例,即可收缩系统数据库。
已知问题
适用于:SQL Server、Azure SQL 数据库、Microsoft Fabric 中的 SQL 数据库、Azure SQL 托管实例、Azure Synapse Analytics 专用 SQL 池
- 在2025 SQL Server之前SQL Server版本(17.x)中,压缩列存储段中大对象(LOB)列类型(varbinary(max)、varchar(max)和nvarchar(max))所使用的页面不能通过
DBCC SHRINKDATABASE和DBCC SHRINKFILE移动。 有关详细信息,请参阅 列存储索引中的新增功能。
了解 DBCC SHRINKFILE 的并发问题
缩小数据库和缩小文件命令可能导致并发问题,尤其是在正在进行(如重建索引)等主动维护时,或在繁忙的在线事务处理(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锁的更多信息,请参见事务锁定与行版本控制指南。
收缩日志文件
对于日志文件,数据库引擎 使用 target_size 计算整个日志的目标大小。 因此,target_size 是执行收缩操作后的日志可用空间。 随后,整个日志的目标大小转换为每个日志文件的目标大小。
DBCC SHRINKFILE 尝试立即将每个物理日志文件收缩到其目标大小。 但是,如果部分逻辑日志位于超出目标大小的虚拟日志中,则数据库引擎将释放尽可能多的空间,并发出一条信息性消息。 该消息说明需要执行哪些操作来将逻辑日志移出位于文件末尾的虚拟日志。 执行操作后,DBCC SHRINKFILE 可用于释放剩余空间。
因为日志文件只能收缩到虚拟日志文件边界,所以可能无法将日志文件收缩到小于虚拟日志文件(即使没在使用它)。 数据库引擎在日志文件创建或扩展时,动态选择虚拟日志文件大小。
最佳做法
在计划收缩文件时,请考虑以下信息:
在执行会产生大量未用空间的操作(如截断表或删除表操作)后,执行收缩操作最有效。
大多数数据库都需要一些可用空间,以供常规日常操作使用。 如果反复收缩数据库文件并注意到数据库大小再次变大,则表明常规操作需要可用空间。 在这种情况下,反复缩小数据库文件反而适得其反。 文件在缩小后分配新空间所需的文件增长可能会影响性能。
收缩操作无法保留数据库中索引的碎片状态,且可能增加索引碎片,从而降低使用大型扫描查询时的读取I/O吞吐量。
如果你需要缩小大型数据库的数据文件,可以考虑使用 ShrinkDriver PowerShell 脚本。 该脚本自动化并简化了缩小过程,使其成为单一、可观察且可恢复的操作。 脚本会并行缩减多个文件,中断时重试,并在运行过程中输出详细的状态报告。
疑难解答
本部分介绍如何诊断和更正在运行 DBCC SHRINKFILE 命令时可能发生的问题。
文件不收缩
如果在无错误的缩小操作后文件大小没有变化,请尝试以下步骤来验证文件是否有足够的空闲空间:
运行以下查询。
SELECT name, size / 128.0 - CAST (FILEPROPERTY(name, 'SpaceUsed') AS INT) / 128.0 AS AvailableSpaceInMB FROM sys.database_files;如果你想缩小事务日志文件,可以使用 sys.dm_db_log_space_usage 动态管理视图(DMV)查看事务日志中使用的空间。
如果空间不足,缩小操作无法进一步减少文件大小。
事务日志文件不变小的一个常见原因是缺乏定期的事务日志备份。 若要截断日志,请备份事务日志,然后再次运行 DBCC SHRINKFILE 操作。 如果不需要点点恢复,可以考虑恢复模型(SQL Server)以避免日志文件增长。
收缩操作受阻
在基于行版本控制的隔离级别下运行的事务可能会阻止收缩操作。 例如,如果在执行 DBCC SHRINKDATABASE 操作时,正在基于行版本控制的隔离级别下运行大型删除操作,那么收缩操作会等到删除操作完成,然后才会继续。 发生此阻塞时,DBCC SHRINKFILE 和 DBCC SHRINKDATABASE 操作会将提示消息(5202 表示 SHRINKDATABASE,5203 表示 SHRINKFILE)打印到 SQL Server 错误日志。 在第一个小时内,此消息每五分钟记录一次,之后每一小时记录一次。 例如:
DBCC SHRINKFILE for file ID 1 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_num 动态管理视图中的 transaction_sequence_numfirst_snapshot_sequence_num 或 first_snapshot_sequence_num 列包含值 15。 如果 transaction_sequence_num 或 first_snapshot_sequence_num 视图列包含的数字小于收缩操作完成的最后一个事务 (109),则收缩操作会等待这些事务完成。
要解决这个问题,请采取以下步骤之一:
- 终止阻止收缩操作的事务。
- 终止收缩操作。 如果收缩操作终止,所有已完成的工作都会保留。
- 不执行任何操作,并允许收缩操作等到阻塞事务完成。
权限
要求具有 sysadmin 固定服务器角色或 db_owner 固定数据库角色的成员身份。
示例
本文中的代码示例使用 AdventureWorks2025 或 AdventureWorksDW2025 示例数据库,可以从 Microsoft SQL Server 示例和社区项目 主页下载该数据库。
答: 将数据文件收缩到指定的目标大小
以下示例将 DataFile1 用户数据库中名为 UserDB 的数据文件的大小收缩到 7 MB。
USE UserDB;
GO
DBCC SHRINKFILE (DataFile1, 7);
GO
B. 将日志文件收缩到指定的目标大小
以下示例将 AdventureWorks2025 数据库中的日志文件收缩到 1 MB。 为了让命令能够 DBCC SHRINKFILE 缩小文件,首先通过将数据库恢复模型 SIMPLE设置为 来截断文件。
USE AdventureWorks2025;
GO
-- Truncate the log by changing the database recovery model to SIMPLE.
ALTER DATABASE AdventureWorks2025
SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 1 MB.
DBCC SHRINKFILE (AdventureWorks2025_Log, 1);
GO
-- Reset the database recovery model.
ALTER DATABASE AdventureWorks2025
SET RECOVERY FULL;
GO
C. 截断数据文件
下面的示例将截断 AdventureWorks2025 数据库中的主数据文件。 需要查询 sys.database_files 目录视图以获得数据文件的 file_id。
USE AdventureWorks2025;
GO
SELECT file_id,
name
FROM sys.database_files;
GO
DBCC SHRINKFILE (1, TRUNCATEONLY);
D. 清空文件
下面的示例展示了如何清空文件,这样文件就能从数据库中删除。 为了方便此示例进行展示,先创建包含数据的数据文件。
USE AdventureWorks2025;
GO
-- Create a data file and assume it contains data.
ALTER DATABASE AdventureWorks2025
ADD FILE (NAME = Test1data, FILENAME = 'C:\t1data.ndf', SIZE = 5 MB);
GO
-- Empty the data file.
DBCC SHRINKFILE (Test1data, EMPTYFILE);
GO
-- Remove the data file from the database.
ALTER DATABASE AdventureWorks2025
REMOVE FILE Test1data;
GO
E. 使用 WAIT_AT_LOW_PRIORITY 收缩数据库文件
以下示例尝试将当前用户数据库中的数据文件的大小收缩到 1 MB。 需要查询 sys.database_files 目录视图以获得数据文件的 file_id,在本例中为 file_id 5。 如果在一分钟内无法获取锁,收缩操作将中止。
USE AdventureWorks2025;
GO
SELECT file_id,
name
FROM sys.database_files;
GO
DBCC SHRINKFILE (5, 1) WITH WAIT_AT_LOW_PRIORITY (ABORT_AFTER_WAIT = SELF);