我有一个包含 850GB MDF 文件的数据库。在 20 个月的时间里,应用程序中的日志记录机制创建了各种巨大的表。只应该在任何时候保留一周数据的维护脚本没有正确执行(现在是)所以我们不得不手动清理。
我们实际上清除了大约 600GB 的数据。我想释放一些空间,因为它所在的驱动器已接近极限。数据文件永远不会再增长到这么大,所以它只是浪费空间。
我打算使用 SHRINK-FILE 来处理这个问题。我已经在数据库的克隆上进行了测试,大约需要 3 个小时。数据库似乎没有任何性能下降。是的,之后索引非常零散,但我可以对它们进行排序。
我的问题是:
应用程序需要在整个过程中保持“运行”状态,因为它很关键。我知道 SHRINKFILE 操作是完全在线的,还是我错了?
数据库几乎每秒都会发生大量写入活动。
SHRINKFILE 操作导致的 I/O 增加会影响这些写入吗?
反过来看,连续写入是否会影响 SHRINKFILE 操作,即使其完成速度变慢?
最后,有没有更好的方法来做到这一点?
更新
仅供阅读本文的任何人使用 - 我运行了 SHRINKFILE 并监控了 I/O 和 CPU。两者都有轻微上升,但我的每秒高写入数数据库根本没有延迟问题。在整个 1.5 小时的 SHRINK 操作过程中,它一直保持运行、稳定且无故障。
之后索引非常零散,这给应用程序的报告端带来了一点麻烦(图表在客户端应用程序上呈现很慢)但是稍后重建了在线索引,一切都恢复了正常。
我们不可能知道它是否会影响应用程序,您也很难确定这一点。即使使用 100% 的同类系统和分布式重放客户端,您也不会注意到磁盘 IO 的毫秒级影响,并且您无法判断应用程序本身对此是否敏感。
唯一可以确定的是供应商自己是否为您提供了一种解决方案来证明它(即应用程序本身可以进行自己的负载测试),恕我直言,很少有供应商拥有这样的东西。
现在到其余部分。
数据文件上的收缩文件会执行大量 IO,这可能会影响对延迟极其敏感的应用程序 - 但我从未见过。如果您的备份没有杀死您,那么这也不太可能杀死您。你必须已经生活在公差的边缘。
作为一名 DBA,您应该始终通过让人们知道发生了什么(正式地通过变更单或非正式地通过其他方式)来掩饰自己。让他们知道没有已知或预期的影响,但如果发生任何事情,您可以立即阻止它。如果您取消收缩文件,它会立即停止。
但除此之外,对我来说,这是一种没有影响的照常变化。我不在金融或医疗保健领域,所以你的标准可能更高。
不过,您确实需要了解以下内容:
您将生成大量日志记录。这意味着您最好处于简单模式或具有非常频繁(每隔几分钟)日志备份的完整模式,以确保您不会开始填满磁盘。
如果您处于完整模式,您将拥有大量 DIFF 备份(如果您这样做),直到下一次完整备份。
在周末,或者每当您的索引维护时段到来时,您都会遇到同样的大量日志备份和 DIFF 备份的情况。如果您的维护确实重建而不仅仅是重组,这可能是个问题;重建可能会将您置于维护窗口之外,在运行时会占用大量日志或临时数据库空间,并爆炸高达数百 GB。如果他们只是在进行重组(即没有中断),那么您只会看到大型日志和 DIFF 备份。
现在所有这些后面的事情肯定会导致中断。但是,如果您有足够的备份空间和磁盘空间用于数据和日志文件,并且每隔几分钟进行一次日志备份,并且只进行重组,并且设置了合理的小的非基于百分比的日志增长大小,那么您不太可能遇到任何麻烦。
收缩将是高度 IO 密集型的,因为它将数据从文件末尾移动到开头(这就是强烈碎片的来源)。不过,这是一个可重新启动的过程,可以随时取消。如果您取消该过程,收缩期间发生的任何数据移动都将保持不变。
您可能想先尝试SHRINKFILE TRUNCATEONLY - 将文件末尾的所有可用空间释放给操作系统,但不在文件内部执行任何页面移动。数据文件仅缩小到最后分配的范围。
如果仍有足够的空间,最好的方法可能是 1) 创建一个新的文件组,2) 使用 ONLINE=ON 开关将表的索引重建到新的文件组中,然后 3) 运行SHRINKFILE 操作以减少原始文件组的占用空间。重建操作是多线程的,而我上次检查的 SHRINKFILE 是一个单线程进程,本质上较慢。您还可以通过预先进行重建来减轻碎片化的副作用。问题是有足够的空间,但是如果您可以在达到卷容量之前将足够多的索引重建到新的 FG 中,那么您将有一个总体上更快的 SHRINKFILE 操作来从原始 FG 中回收空间。