我有一个数据库文件,目前大小为 150GB,但只使用了 75GB - 这是因为我将所有索引(其余 75GB)移到了一个新的数据文件中。我想从这个数据文件中回收至少一部分空间,但当我尝试缩小文件时,它会无限期地“执行”,最终由于网络中断或其他我无法控制的原因(运行一天后)而被取消。即使使用“缩小到特定大小”功能并指定它只削减 10MB,它似乎也永远不会恢复 - 它只是处于静止状态,直到进程被中断。
还有其他方法可以让我重新获得这个空间吗,哪怕一次只恢复一点点?
编辑:有人发布了一个链接,解释了为什么我不应该缩小数据库。我明白,无论如何我都想缩小它。这台服务器上的磁盘空间非常宝贵,数据库很长时间内不会再次扩展到这个未使用的空间 - 正如我之前所说,我将索引从数据文件中迁移出来以释放这个空间,所以现在它被浪费了。
答案1
不,使用DBCC SHRINKFILE ('filename', target_size)
才是正确的方法。
如果您想以“块”的形式执行此操作,您可以逐步设置更小的目标大小,或者让它尽可能长时间运行直至被取消。
一些评论:
- 设定一个合理的目标大小,并留出一些允许的可用空间。也许 75GB 的数据总共需要 90GB?
- 在收缩过程中,检查活动监视器以查看 SPID 是否被阻止。如果文件末尾的页面上有一个打开的事务,则收缩将无法移动它,直到该事务提交或回滚。
- spid 是否确实取得了进展?(CPU 和 IO 数量正在发生变化)
- 收缩有时会花费很长时间,但它应该保存进度(意味着它每次移动 1 页,当它被取消时,所有完成的页面移动都已完成)
- 取消收缩后,尝试执行
DBCC SHRINKFILE ('filename', TRUNCATEONLY)
。它应该恢复文件末尾已释放的所有空间(参见我之前的观点) - 如果您感到绝望,请尝试在单用户模式下重新启动 SQL,这样您就知道当时没有其他任何操作正在对数据库进行操作(显然,这在生产服务器上是不可能的)
- 一旦能够完成收缩,请确保对数据库进行完整的重建索引,以消除收缩造成的碎片。这可能会回收您刚刚释放的一些空间。
- 如果你仍然无法让收缩起作用,请查看这个问题显然,有些情况下心理医生可能无法取得进展。
答案2
在我们的环境中,我们考虑了几种选择:
- 如果旧表可以面向外,则在全新文件组上创建新表并将数据库默认为该文件组。随着时间的推移,删除旧表,直到先前的文件组为空。然后将其删除。
- 如果旧表无法调出但包含可离线数小时的历史数据,请创建一个指向新文件组的新空表。交换表并开始批量将行从旧表复制到新表。但这可能会导致碎片。
- 发出带有 EMTPYFILE 选项的 DBCC SHRINKFILE,数据库会将所有对象移动到新文件。然后您可以删除旧文件。不过这可能需要很长时间。
- 将所有表的聚集索引(带有 DROP_EXISTING 的主键)重新创建到新文件组中。但这会锁定表。
祝你好运
答案3
如果您不想简单地回收空间(您明确拒绝这样做),而是坚持尝试缩小数据库,那么这将花费非常长的时间,并且您的事务日志扩展应该刚好覆盖您从数据库回收的任何空间。作为奖励,之后观察您的数据库性能是否下降。如果 Paul Randal 无法说服您(JL 对此进行了评论,但我会在此处重新发布:为什么不应该缩小数据文件收缩是一个糟糕的想法,我不确定是否有人能做到。如果幸运的话,收缩将在下一次修订中从 SQL Server 中删除(或至少进行更改,使其按照 Paul 的建议工作)。