ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Sqlserver2000数据库文件越删越大?用DBCC命令深度压缩释放空间

Sqlserver2000数据库文件越删越大?用DBCC命令深度压缩释放空间 简介面向SQL Server 2000数据库管理员与维护人员的深度压缩数据库文件指南主要解决通过企业管理器收缩效果不佳、冗余空间无法彻底释放的典型问题。文档以docx格式提供共1个文件包体大小256KB方便直接阅读或打印对照。内容围绕DBCC SHRINKDATABASE、DBCC SHRINKFILE与DBCC UPDATEUSAGE三条核心命令展开详细说明了从查询sysfiles获取文件ID、收缩数据库、收缩数据文件与日志文件到更新文件使用统计的完整思路同时强调操作前备份、关注压缩对性能与碎片的影响帮助读者规避常见风险。已有310人学习下载适合正在维护SQL Server 2000实例并需要清理数据库文件空间的DBA或运维人员参考。通过这份文档读者可以掌握一套比图形界面更深入的数据库文件压缩方法有效释放删除操作遗留的占用空间。1. Sqlserver2000 数据库文件越删越大真正释放空间的入口在 DBCC 命令做 Sqlserver2000 维护的人大概率经历过这个场景生产库频繁 delete 历史数据磁盘上的 .mdf 文件却纹丝不动企业管理器里的收缩数据库点了一遍又一遍界面提示完成文件还是几个 GB。这不是错觉——图形界面的收缩机制只处理文件末尾的空闲页被删除记录留下的空洞早就分散在文件中间了。要解决 Sqlserver2000 数据库文件的冗余空间问题真正的入口在查询分析器里的 DBCC 命令查 sysfiles 拿 fileid用 DBCC SHRINKDATABASE 整体收缩再用 DBCC SHRINKFILE 按数据文件和日志文件分别收缩最后用 DBCC UPDATEUSAGE 修正统计信息。这套深度压缩流程适合维护老系统的工程师、迁移归档前要腾空间的团队以及被库越删越大折磨的开发和运维。下面按实际操作顺序把每一步命令、参数含义和最容易翻车的地方讲透。2. 压缩前必修课备份、sysfiles 查询与 fileid 的含义2.1 为什么企业管理器的收缩数据库经常不彻底先别急着敲命令得先搞清楚一个核心问题同一个库为什么用企业管理器收缩和用 DBCC 命令收缩效果差这么多企业管理器里的收缩数据库对话框本质上是封装了 DBCC SHRINKDATABASE 的图形界面但它的默认收缩策略偏保守。工作逻辑是把文件末尾的空闲页尽量往前挪然后从文件尾部截断释放空间。如果空闲空间集中出现在文件末尾这种方式一次就能缩出效果但经历大量 delete、update 操作之后的 Sqlserver2000 库空闲页是零散分布在整个文件中间的文件末尾往往没有足够多的连续空闲页可以释放。于是界面显示收缩完成实际上文件大小几乎没变。这里有一个非常普遍的误解以为收缩数据库就是把已删除的数据清掉。delete 操作在 Sqlserver2000 里只是把数据页标记为可复用文件里的空间并没有真正还给操作系统。收缩做的是重新组织页的位置把空闲页集中到文件尾部再释放而不是擦除数据。所以收缩的下限是当前实际数据量 必要的空闲空间指望把 10GB 的库缩成 1GB 是不现实的除非那 9GB 真的全是空闲页。我一般会先做一次快速体检再决定要不要深度压缩用 sp_spaceused 查实际数据占用用 sysfiles 查文件大小两者差距超过 30%说明冗余空间值得处理。比如一个订单历史库数据文件 8GBsp_spaceused 显示实际占用只有 3.2GB这种库就该走一遍完整的 DBCC 流程如果差距只有几个百分点收缩的收益很低不如把精力放在索引维护上。这个判断标准在 Sqlserver2000 上很实用因为收缩过程本身有代价不是每次收缩都划算。2.2 查询 sysfiles确认 fileid 与文件类型确认值得收缩之后第一个实际操作是查 sysfiles。在查询分析器里通过工具栏的数据库下拉框选中目标库然后执行-- 查看当前数据库的文件信息确认 fileid 与物理文件路径 SELECT fileid, groupid, size, name, filename FROM sysfiles执行结果里最关键的是 fileid 列。Sqlserver2000 默认创建的数据库通常有两个文件fileid 为 1 的是主数据文件.mdffileid 为 2 的是日志文件.ldf。后面执行 DBCC SHRINKFILE 时第一个参数填的就是这里的 fileid 值。有几个字段需要特别说明。size 列的单位不是字节也不是 KB而是 8KB 页数换算成 MB 要乘以 8 再除以 1024。filename 列是物理路径如果这个库后来加过数据文件或者文件组fileid 可能超过 2这时候不能想当然地认为 1 是数据、2 是日志必须以 filename 列的扩展名为准。groupid 表示文件属于哪个文件组默认 0 是主文件组status 列跟文件状态位有关日常收缩用不到。查询到结果后我习惯顺手把两组值抄到旁边一组是数据文件的 fileid 和当前大小一组是日志文件的 fileid 和当前大小。收缩完成后再拿同样的查询结果做对比就能快速判断每步命令到底起了多大作用。2.3 备份策略深度压缩前必须完成的兜底动作DBCC 收缩会物理移动数据页这个操作不可逆。一旦执行过程中遇到断电、磁盘错误或者目标值填错导致文件被异常收缩数据受损后基本没有后悔药。所以我在任何生产库上执行深度压缩之前都强制要求先做一次完整备份-- 完整备份到独立路径文件名带上日期便于追溯 BACKUP DATABASE [your_db_name] TO DISK ND:\backup\your_db_name_20050101.bak WITH INIT, NAME Nyour_db_name 深度压缩前备份这段命令里WITH INIT 表示覆盖同路径下的同名备份文件防止历史备份被新备份混掉NAME 是备份集的描述信息将来恢复时可以通过它识别这次备份的用途。备份文件建议放到与数据库不同的物理磁盘上避免同一块盘故障时数据和备份一起丢。备份完成之后我还会多执行一步校验用 RESTORE VERIFYONLY 确认备份文件物理完整可读-- 校验备份文件的完整性不实际恢复库 RESTORE VERIFYONLY FROM DISK ND:\backup\your_db_name_20050101.bak这一步很多老工程师会跳过但真到要恢复才发现备份损坏的情况我见过不止一次。校验通过后再进入收缩阶段之后所有操作都建立在最坏情况能回滚的前提下。2.4 恢复模式与日志收缩的关系动手前先看清库的配置深度压缩里最容易被忽略的背景知识是恢复模式。Sqlserver2000 的恢复模式分为简单、完整和 bulk-logged 三种它直接决定了日志文件能不能顺利收缩。简单模式下事务日志在检查点会被自动截断活动日志部分很小DBCC SHRINKFILE 收缩日志通常很顺利。完整模式下日志会一直保留到执行 BACKUP LOG 为止如果长时间没做日志备份日志文件里大部分空间被旧日志占着收缩命令会被活动日志挡住表现为执行成功但文件不缩小。所以在备份数据库之后我一般顺手查一下恢复模式-- 查看当前数据库的恢复模式判断日志收缩的难度 SELECT DATABASEPROPERTYEX(your_db_name, IsRecoveryMode) AS recovery_mode返回的字符串里 SIMPLE 是简单模式FULL 是完整模式。如果是 FULL收缩日志前先执行一次 BACKUP LOG把活动日志截断-- 完整模式下先备份日志再收缩日志文件 BACKUP LOG [your_db_name] TO DISK ND:\backup\your_db_name_log_20050101.trn这个前置动作很多人不知道结果反复执行 SHRINKFILE(2, 0)日志文件纹丝不动还以为是命令写错了。先截断日志、再收缩日志文件、最后收缩数据文件这个顺序在 Sqlserver2000 上能少走很多弯路。3. 整体收缩DBCC SHRINKDATABASE 的用法与效果边界3.1 执行 DBCC SHRINKDATABASE默认收缩到最小选好目标库确认备份已完成恢复模式也摸清了接下来执行整体收缩-- 使用目标库避免上下文选错 USE [your_db_name] GO -- 整体收缩数据库默认收缩到最小可能大小 DBCC SHRINKDATABASE(your_db_name) GO执行后查询分析器会输出每类文件的处理结果。DBCC SHRINKDATABASE 的作用范围是整个数据库包括所有数据文件和日志文件它是深度压缩的预处理阶段先把能释放的空间整体释放一轮。加不加 USE 语句差别很大DBCC SHRINKDATABASE 虽然带了库名参数但查询分析器里如果当前上下文是 master某些情况下的执行会影响其他系统对象的统计我每次都先用 USE 锁定再执行命令避免选错库这种低级事故。这个命令是整体思路它对每个文件都尝试收缩但不保证每个文件都能达到最小尺寸。数据文件能不能缩到位取决于文件末尾是否有可释放的连续空闲区日志文件能不能缩取决于活动日志的位置。所以这一章的结果往往不够惊艳真正的精细控制在下一章。3.2 参数说明target_percent、NOTRUNCATE 与 TRUNCATEONLYDBCC SHRINKDATABASE 的完整语法是DBCC SHRINKDATABASE (database_name [, target_percent] [, {NOTRUNCATE | TRUNCATEONLY}])第二个参数 target_percent 表示收缩完成后文件中保留的空闲空间百分比。填 0 或省略表示收缩到最小填 10表示收缩到数据占 90%、空闲占 10%的状态。实际维护里我很少填百分比因为 Sqlserver2000 的年代硬盘空间金贵一般都是直接压到最小再由 SHRINKFILE 按目标大小精细控制。第三个参数的两个选项特别容易理解反用一张表说明参数/选项作用适用时机target_percent 0收缩到最小可能大小深度压缩默认选项target_percent N保留 N% 空闲空间给数据增长留余量NOTRUNCATE把末尾页搬到文件前部但不释放文件空间先整理页分布为截断做准备TRUNCATEONLY只释放文件末尾的连续空闲空间不搬移任何页文件末尾有空闲区时快速释放常见做法是两步组合先 NOTRUNCATE 整理页分布再 TRUNCATEONLY 释放空间。不过要提醒的是对深度压缩来说这两步只是辅助真正的空间释放大头在下一章的 SHRINKFILE。一个库如果经历过大量删除单靠 SHRINKDATABASE 很难缩到理想大小这一点要有心理预期。3.3 为什么整体收缩后文件尺寸仍然偏大执行完 DBCC SHRINKDATABASE满怀期待去看文件大小发现 .mdf 只小了一点点甚至没变这是最常见的失望时刻。原因通常有三个。第一日志文件的活动部分挡住收缩。如果完整恢复模式下没做过日志备份或者有长事务一直没提交日志文件的活动部分位于文件靠后的位置DBCC SHRINKDATABASE 无法跨过它释放尾部的空间。第二数据文件内部碎片依旧。大量删除留下的空闲页散布在文件中间整体收缩只在文件末尾做截断释放中部的空洞继续存在。第三target_percent 设得太大比如填了 50收缩完还剩一半空闲空间当然看不出明显变化。这三个原因都可以通过后续的 SHRINKFILE 来修正或规避。所以整体收缩的定位更适合理解成预处理把好搬的页先搬走把日志截断的时机校准然后交给按文件收缩来处理。在深度压缩的完整链路里这步可以快进但不能跳过。3.4 收缩结果的输出解读与常见报错DBCC SHRINKDATABASE 执行完结果窗口会打印一段信息。Sqlserver2000 的查询分析器里正常输出是类似DBCC 执行完毕。如果 DBCC 输出了错误信息请与系统管理员联系。这样一句话。如果在这之前出现了别的输出比如无法收缩日志文件 2因为该文件末尾的逻辑日志文件正在使用说明日志活动部分挡路了需要先回去执行 BACKUP LOG。我习惯把执行前后的输出文本都保留在查询分析器里和 sysfiles 的查询结果放在同一个标签页。一旦结果不符合预期可以往回翻对照哪一步输出异常。Sqlserver2000 的 DBCC 报错信息有时比较隐晦比如提示文件被其他进程占用往往意味着有其他会话正在这个库上跑事务收缩会一直等待。用 sp_who 查一下阻塞源杀掉冲突会话再重试比傻等有效得多。4. 按文件精细收缩DBCC SHRINKFILE 的参数、顺序与效果验证4.1 用 fileid 精确定位数据文件与日志文件深度压缩的关键命令是 DBCC SHRINKFILE它只针对单个文件操作。使用前回到第 2 章的 sysfiles 结果确认两个 fileid 的值。标准 Sqlserver2000 库里fileid 1 对应数据文件 .mdffileid 2 对应日志文件 .ldf。如果库加了多个文件组每个文件都有自己的 fileid收缩时要用 filename 列的扩展名区分角色而不是靠序号猜。按文件收缩的标准顺序是先日志后数据。日志文件的收缩逻辑简单通常几秒到几十秒就能完成可以快速验证命令参数是否正确数据文件收缩要逐页搬移数据耗时可能很长放到后面执行更稳妥。-- 先收缩日志文件target_size 为 0 表示收缩到最小 DBCC SHRINKFILE(2, 0) GO -- 再收缩数据文件 DBCC SHRINKFILE(1, 0) GO执行后查询分析器输出正在将页从文件末尾移动到文件开头附近之类的进度信息之后出现DBCC 执行完毕表示成功。如果输出提示无法收缩通常是文件里有内容阻止了收缩比如数据文件的某个对象不允许页移动或者日志活动部分挡路。4.2 第二个参数0 到底代表什么DBCC SHRINKFILE 的完整语法是DBCC SHRINKFILE ({file_id | file_name}, target_size [, {NOTRUNCATE | TRUNCATEONLY}])第一个参数可以是 fileid 数字也可以是 sysfiles 里的 name 字段字符串第二个参数 target_size 的单位是 MB指的是收缩后的目标文件大小。填 0 是深度压缩里最常见的用法含义是收缩到最小可能大小。对数据文件来说就是收缩到能容纳当前数据的最小尺寸通常接近文件初始分配的大小对日志文件来说就是截断到最小可能尺寸。target_size 填错会造成两种后果。填一个小于实际数据量的值比如数据文件实际占用 800MB你填 500MB命令不会立即报错而是把目标自动调整到实际占用附近再收缩结果与预期不符。填一个过大的值比如库总共 2GB 你填了 1900MB就只能从末尾释放一点点空间看起来像没效果。实际维护中我基本不把数据文件直接缩到 0。Sqlserver2000 的文件自动增长是一次性分配大片空间频繁触发增长会在磁盘上造成文件碎片还有可能在增长瞬间阻塞写入。常见做法是先查 sp_spaceused 得到数据实际占用再在这个数值上加 20% 到 30% 的余量作为目标值。比如实际占用 800MB就填 1024让文件收缩到 1GB既释放了空间又给后续增长留了缓冲。提示DBCC SHRINKFILE 的第二个参数单位是 MB不是百分比。填数字之前先算清楚别把 20 当 20% 用。4.3 多文件库与日志文件的收缩细节如果是多文件库收缩策略要单独规划。Sqlserver2000 允许把表和索引分布到不同文件组收缩时应该针对空闲比例最高的文件下手而不是平均对待每个文件。sysfiles 查询结果里 size 列最容易看出哪个文件冗余多size 大但实际数据少的文件优先收缩。日志文件的收缩有个前提条件先截断日志。完整恢复模式下先 BACKUP LOG 再 SHRINKFILE简单恢复模式下日志在检查点自动截断直接收缩即可。收缩日志的目标值也别填 0 填得太狠日志文件内部有虚拟日志文件VLF结构缩到过小会导致后续事务频繁等待日志增长。我一般把日志文件保留在 256MB 到 512MB 这个量级具体看这个库的事务量核心交易库可以留到 1GB。4.4 收缩过程观察与效果验证数据文件的收缩是逐页搬移。一个几十 GB 的库缩到目标大小可能要跑十几分钟。执行期间别关查询分析器会话也别同时在同一个库上跑大事务否则收缩会被阻塞甚至回滚。时间太长的话可以分段收缩先缩到 2048MB再缩到 1024MB最后缩到目标值每次搬移的页数少一些对在线业务的影响小一些。判断收缩是卡住了还是在干活看查询分析器状态栏和输出窗口的进度信息。Sqlserver2000 的 DBCC 在搬页过程中会持续输出正在移动页之类的信息如果长时间没有任何输出且 sp_who 显示该会话处于等待状态多半是被其他事务阻塞了而不是死机。收缩完成后立刻对比 sysfiles-- 收缩后重新查询文件大小单位换算为 MB SELECT fileid, size * 8 / 1024 AS size_mb, name, filename FROM sysfiles把这里的 size_mb 和第 2 章记录的收缩前数值放在一起看能直观确认每个文件各缩了多少。如果某个文件大小没变回到上一章的原因列表排查日志活动部分挡路、目标值过大、或者文件里有关键对象不允许移动页。5. 深度压缩避坑指南五条让数据库翻车的实战记录深度压缩本身不复杂复杂的是那些藏在命令背后的边界条件。以下五条都是我在实际维护里踩过或者帮人收拾过的坑按现象、原因、解决记录在这里。5.1 坑一未备份就收缩误操作后没有后悔药现象跳过备份直接执行 DBCC SHRINKFILE结果目标值填小文件被异常收缩搬页过程中遇到磁盘坏道数据库进入可疑状态业务直接中断。原因收缩会物理搬移数据页是不可逆操作。Sqlserver2000 没有类似回收站的机制文件末尾空间一旦释放原位置的数据页就没了。遇到断电、坏道这类叠加故障时没有备份等于没有退路。解决任何生产库执行深度压缩前必须先完成完整备份并用 RESTORE VERIFYONLY 校验备份可用。这条没有任何例外哪怕只是缩一个几十 MB 的小库也要遵守。备份文件保留到确认收缩结果正常、业务验证通过之后再清理。5.2 坑二把 SHRINKFILE 的第二个参数当成百分比填现象有人写 DBCC SHRINKFILE(1, 20)本意是收缩到剩余 20% 空闲空间结果文件被缩到一个预料之外的小尺寸或者因为目标值小于实际数据量而被系统自动调整收缩结果与预期完全对不上。原因SHRINKFILE 的 target_size 单位是 MB不是百分比。20 表示 20MB而不是 20%。这个误会在 Sqlserver2000 年代尤其常见因为 SHRINKDATABASE 的第二个参数是百分比换了命令之后单位跟着变习惯却没变。解决填数字之前先算清楚。用 sp_spaceused 查实际数据占用目标值等于实际占用乘以预留系数。想省事就填 0 收缩到最小再手动为文件设置合理的初始大小不要凭感觉填一个数。5.3 坑三频繁收缩导致索引碎片化查询反而变慢现象一个报表库每个月都做深度压缩磁盘空间一直很健康但业务方反馈查询越来越慢简单条件查询有时候要好几秒。原因收缩过程会搬移数据页破坏索引页的逻辑顺序与物理顺序的对应关系碎片率大幅上升。Sqlserver2000 的查询优化器面对高度碎片化的索引扫描成本剧增本来走索引的查询变成了大面积扫页。解决深度压缩完成后对核心表执行 DBCC DBREINDEX 或者 DBCC INDEXDEFRAG把碎片率压回去。同时把收缩频率降下来不是每次空间紧张都值得深度压缩。空间利用率低于 85% 的库优先做索引维护而不是收缩。5.4 坑四日志文件缩到 0 后事务日志备份失败现象把日志文件用 DBCC SHRINKFILE(2, 0) 缩到很小之后执行 BACKUP LOG 时报错或者事务日志异常增长几分钟就写满。原因日志文件内部有虚拟日志文件VLF结构过度收缩会把日志文件截断得过小后续事务需要频繁等待日志增长某些情况下还会把当前活动日志的位置弄乱导致日志备份无法定位起始点。解决日志文件不要缩到 0建议保留一个合理尺寸比如 512MB 或 1GB给日常事务留出缓冲。收缩日志前先执行 BACKUP LOG把活动日志截断再收缩成功率会高很多。5.5 坑五收缩完没执行 DBCC UPDATEUSAGE统计信息对不上现象收缩完成后sp_spaceused 显示数据库已用空间只有几百 MB但磁盘上的 .mdf 文件还是 2GB数据文件大小怎么都对不上。原因收缩释放了页面但 sysindexes 系统表里记录的空间使用统计没有同步更新导致报告的已用空间和实际文件大小出现偏差。解决执行 DBCC UPDATEUSAGE(0)这里的 0 表示所有数据库。只更新当前库也可以直接执行 DBCC UPDATEUSAGE但整个实例一起更新更省心。这一步放在收缩命令全部执行完之后作为收尾动作之后再查 sp_spaceused 就是准确数字了。6. 验证压缩结果与后续维护把深度压缩变成固定巡检习惯深度压缩不是一次性的救火操作它应该是一套固定巡检流程的组成部分。我自己的习惯是每次做完收缩强制走一遍完整的验证与收尾链路。第一步是再次查询 sysfiles对比收缩前后的 size_mb确认数据文件和日志文件都达到了预期目标而不是只看数据库总体大小。第二步执行 DBCC UPDATEUSAGE(0)把空间统计刷一遍然后用 sp_spaceused 核对已用空间与文件大小的比例正常情况下差距应该明显缩小。第三步检查索引碎片必要时执行 DBCC DBREINDEX 或 DBCC INDEXDEFRAG把收缩带来的页搬移副作用消除掉。把这套动作写成一个固定维护脚本每次巡检时按顺序跑备份、查 sysfiles、SHRINKDATABASE、SHRINKFILE、UPDATEUSAGE、重建索引、再次对比。Sqlserver2000 没有后来版本的自动化维护计划那么方便但查询分析器支持把一批 SQL 存成 .sql 文件配合操作系统计划任务也能做到定期执行。脚本里每个命令之间最好加上 GO 分隔并把关键步骤的输出保留到日志文件里方便事后审计。有一点我想特别强调深度压缩的空间收益是有上限的它释放的是冗余空间不是数据量本身。如果每次巡检都发现文件缩完很快又涨回去说明业务数据量在真实增长这时候应该做的是扩容规划或者数据归档而不是继续依赖收缩腾空间。收缩用得太频繁索引碎片、文件增长碎片和 I/O 性能问题会接踵而来这是很多老库越维护越慢的根本原因。说回我自己的教训早年维护一个 Sqlserver2000 的老库存系统为了省磁盘空间一个月做两次深度压缩结果索引碎片越来越严重月底出报表慢得离谱。后来改成先备份、再收缩、强制重建索引的三段式流程并且只在空间利用率超过 85% 时才触发深度压缩系统的查询性能才稳定下来。从那以后每次对数据库做深度压缩我都强制走一遍完整的备份、收缩、统计更新、索引重建链路不再贪图一条命令搞定。希望帮到你。本文还有配套的精品资源点击获取
返回列表