一、 前言
听ai的建议,取个唬人的标题热度会不会好一点🤔
今天登录数据库时偶然发现一个现象,一个项目使用的 SQL Server Express数据库,数据文件(MDF)仅有 800MB 左右,但日志文件(LDF)却疯狂扩张到了12G多,这显然不太对劲。
虽然 SQL Server Express 版对单库数据有 10GB 的“硬限制”,但这个限制并不包含日志。这意味着,如果不加以干预,日志会跟个失控的肿瘤一样,无限变大,直到崩坏的一刻。
预算充足,或者项目的数据量在中等规模以上,使用MSSQL作为关系数据库的,非极端情况下不要使用Express版本。
二、 为什么日志会“只增不减”?
如果不是专业的DBA,大部分的开发者可能都会忽略 SQL Server 的恢复模式(Recovery Model) 逻辑,笔者本人也是发现问题后GPT并查阅了一番才确认问题(官方文档:learn.microsoft.com/en-us/sql/r…
在该数据库的属性中,它的恢复模式被设为了“完整”模式。
在这一模式下,SQL Server 的处理逻辑是:
“我会记录每一个字节的变更。除非你手动进行了‘事务日志备份’,否则我认为这些记录对你依然‘有用’,我绝不会覆盖它们。”
然而,在实际的运维场景中,我们只做了“按天全量备份”,并定期清除早期备份释放空间,而没有配置每小时或每十分钟的“事务日志备份”,那么此时完整模式就变成了一个空间黑洞,它空有强大的“点对点恢复”能力,却因缺乏备份链的触发而成了现在这种只收纳不清理的样子。
三、 推敲
怎么处理这个超大个的日志文件?当然是释放掉!
- 首先,我们已经有了备份的逻辑,按天完整备份,特殊情况手动及时备份,因此“完整”模式在这个场景下,是不必要的;
- 其次,性能影响,尤其是写入性能,包括MSSQL在内的大部分关系数据库都是先写日志再写数据,而且每次增长都会申请新的磁盘空间,当下的日志量这么大,会成为严重的拖油瓶;
- 最后,我们的业务大概率不需要“点对点恢复”的模式,也不会去折腾这个复杂的备份链路,还要打上日益紧张的磁盘空间。
因此,与其追求那种“看起来很美”但没人维护的完整恢复能力,不如换取一个“清爽、稳定、不用操心”的系统环境。运维不就是这样吗?没有最好的方案,只有最适合当前业务现状的取舍。拒绝过度设计,也是一种技术路线。
这个只是我这边的处理决定,落到实际,大家如果所在团队有经验丰富的DBA在,或者有完备的数据库运维经验,建议听取专业意见后再决定如何处理。
四、 脚本开干
虽然MSSQL一般都会搭配一个好用而且是官配的SSMS,但还是建议通过脚本来完成,不会的可以GPT,操作逻辑更加严密。
- 切换模式
ALTER DATABASE [YourDB] SET RECOVERY SIMPLE WITH NO_WAIT;
这一步跟在SSMS的可视话窗口里修改的结果是一样的。
- 物理收缩 (Shrink)
修改模式并不会自动缩小物理文件,需要手动回收操作系统层面的空间,这里我设置成了500MB。。
DBCC SHRINKFILE (N'YourDB_Log' , 500);
注意,参数里“YourDB_Log”是逻辑名,有的逻辑名和数据库名是不一致的,要自行确认一下;
- 验证执行结果
SELECT name AS [逻辑名], size*8/1024 AS [当前大小(MB)], max_size AS [最大限制], physical_name AS [物理路径]
FROM sys.database_files;
GO
- 立刻备份
这是关键的一步。 改变恢复模式会破坏原有的备份连续性。操作完成后,必须立即触发一次全量备份,建立新的安全基准点。
BACKUP DATABASE [MATCH_HT]
TO DISK = N'{路径&文件名}.bak'
WITH FORMAT, INIT,
NAME = N'全量备份',
STATS = 10;
GO
结语
这次分享的同时,我本人也学到了一点碎片化的知识。最后还是要提醒,本文分享的释放日志空间的方式不是一种普适方法,要根据具体情况而论。然后,不仅是 MSSQL,几乎所有基于 WAL(Write-Ahead Logging) 机制的数据库(如 MySQL 的 Binlog、PostgreSQL 的 WAL、Oracle 的 Redo Log)都面临类似的挑战。
总之吧,当下这个时代,只关注单一层面的技能肯定是竞争力越来越不够看,尤其在小厂,硬分什么前端,后端,运维,算法...各种岗位,也不太现实,只能是把自己逼成“全干”的岗位,这是在吃苦,但也是一种锻炼,某种程度来说,还可能是一种幸运,艺多不压身。当然我绝不是在倡导内卷或者“没苦硬吃”,价值观还是要摆正,只要结果是积极的正向的,不论是对团队还是对个人,就都是有价值的。
好了,就聊这些。