大促后数据库慢SQL的集中治理,核心就一句话:先快速止血归档历史数据,再系统优化高频SQL,最后用索引与执行计划兜底。
大促后数据库慢查询怎么排查:先看等待事件再拆执行计划
大促结束后的头两天,数据库就像被塞满的仓库,订单表、日志表、用户行为表集体膨胀,此时最忌讳一上来就无脑加索引,因为你可能连慢在哪张表、哪条SQL、卡在锁还是卡在扫描都还没定位清楚。
排查慢查询的第一层动作是打开慢查询日志,MySQL默认的slow_query_log处于关闭状态,很多团队在大促前会临时关闭它来节省性能消耗,大促后经常忘记重新打开,先把阈值调低至一秒,这样才能抓到足够多的样本。
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = 'ON';
日志打开后,不要手动一条条翻,直接用Percona Toolkit里的pt-query-digest做聚合,它会按执行时间、执行次数、锁等待时间排序,最慢的几条SQL会自己冒出来,这就是第二层动作:找出Top SQL。
第三层动作是看执行计划,对Top SQL执行EXPLAIN ANALYZE(MySQL 8.0以上支持),这一步能把实际扫描行数、是否走索引、临时表开销都摊在桌面上,很多慢SQL的问题根本不是索引缺失,而是大促期间写入量暴增后,统计信息已经过期,优化器选错了执行路径。
第四层动作是登入实例看实时状态,执行SHOW FULL PROCESSLIST,重点观察State列里是否有Waiting for table metadata lock或Sending data长时间不结束的线程,如果有锁等待,先处理锁源,别急着优化SQL。
慢日志量太大怎么快速定位
大促后单日慢日志可能积累几个GB,此时可以按表名过滤,例如只保留订单表相关的慢日志:
pt-query-digest /var/log/mysql/slow.log --filter '$event->{db} eq "shop" && $event->{arg} =~ m/orders/i'
也可以直接查询performance_schema.events_statements_summary_by_digest,按总耗时降序取前20条,这个系统视图不需要解析慢日志文件,响应更快。
慢SQL治理和索引优化哪个更有效:大促后的答案是先归档数据
很多研发会问:“慢SQL治理和索引优化哪个更有效?”这个问题在大促后的特定场景下,答案非常明确:先归档数据,再谈索引优化,两者不是替代关系,但存在明确的优先级。
索引优化解决的是检索效率问题,它能让数据库从全表扫描变成索引定位,但在单表数据量暴涨数倍的情况下,索引的收益会明显衰减,原因很直接:即使走二级索引,回表操作依然要访问主键索引,数据页缓存命中率下降,磁盘IO急剧增加。
归档解决的是数据规模问题,把30天以前的历史订单迁移到归档表,主表体积可能直接缩小一半以上,体积降下来后,原本慢的SQL可能不用优化就恢复到可接受范围,业内专家指出,大促后的慢SQL治理窗口期通常只有一周左右,如果错过这个时段,雪片般的用户投诉会倒逼运维做更加激进的临时方案。
所以正确顺序是:先归档止血,再针对剩余高频慢SQL做索引优化,这个顺序不能反过来,一个人仓库堆满杂物,你应该先把旧货搬走,而不是急着调整货架标签。
为什么只加索引救不了大促后的慢查询
表里有几千万行新数据,就算你给create_time加索引,范围扫描依然可能命中上百万行,再加上回表随机IO,单次查询照样超过一秒,索引不会减少数据量,它只是改变了访问路径,大促后的核心矛盾是数据膨胀,不是访问路径错误。
电商大促后订单表归档操作方法:按月分区与历史表迁移
电商大促后订单表归档操作方法有两条成熟路径:分区表交换和工具批量迁移,选哪条取决于你的表结构是否已经分区。
如果订单表在建表时就按月份做了RANGE分区,归档操作会非常干净,例如按create_time每月一个分区,直接清掉三个月前的分区即可:
ALTER TABLE orders TRUNCATE PARTITION p202610;
这条命令执行速度极快,因为它不是逐行删除,而是直接释放整个分区的数据文件,代价是要求表在设计阶段就有分区规划,大多数存量系统没有这个条件。
没有分区的表,推荐用pt-archiver做在线迁移,它会按主键顺序分批读取、写入归档表、再删除源表记录,每批之间自动提交事务,不会造成大事务锁表。
pt-archiver --source h=127.0.0.1,D=shop,t=orders \
--dest h=127.0.0.1,D=shop,t=orders_archive \
--where "create_time < DATE_SUB(NOW(), INTERVAL 30 DAY)" \
--limit 1000 --commit-each --progress 5000
执行前需要确认几件事:历史表orders_archive结构与源表完全一致;归档条件字段有索引;业务层对历史数据无强一致写需求,迁移过程中会产生一定量的binlog,建议错开业务晚高峰执行。
用时间分区还是pt-archiver更稳妥
分区表交换速度快但需要提前规划,对现有表改分区通常要在线DDL,成本不低。pt-archiver灵活通用,但迁移速度受主键扫描和网络吞吐限制,多数情况下,存量业务用pt-archiver,新建业务用分区表,这是行业共识。
归档后还需要做的三件事:统计信息、索引整理与冷数据查询
数据归档完成不代表治理结束,主表体积突然变化后,优化器依赖的统计信息已经不准了,第一件事是对主表执行统计信息更新:
ANALYZE TABLE orders;
这一步会重建索引基数估算值,避免优化器因为过期的统计信息继续选择低效执行计划。
第二件事是整理冗余索引,大促前很多团队为了应急临时加过索引,归档后数据量下降,部分索引可能变成纯维护成本,用pt-duplicate-key-checker扫描冗余索引,评估后删除,删除动作要小批量进行,一次删一个索引,观察慢日志变化。
第三件事是规划冷数据查询通道,历史订单数据虽然不参与线上高频交易,但客服、对账、用户中心等场景仍要查询,归档表可以继续留在同库实例,但建议改为按月分区存储,若数据量继续增长,可定期将超过一年的分区导出为Parquet文件放到对象存储,通过外部表或离线数仓查询。
北京地区数据库性能优化服务价格与自建归档脚本的成本对比
北京地区数据库性能优化服务价格的影响因素主要看问题复杂度、实例数量和治理周期,多数服务商按人天计费,慢SQL治理加归档方案设计通常需要数天到两周不等,价格差异较大,具体数字受服务商资质、驻场要求和响应时效影响,不做精确承诺。
自建归档脚本的显性成本是DBA的投入时间,一个熟练DBA完成pt-archiver部署、验证、执行与监控,首次大约需要一天,后续复用脚本几乎零额外成本,隐性成本在于出问题时的恢复难度:归档误删数据、迁移中断、主备延迟放大等,如果没有充分备份和演练,自建方案的风险并不低。
对大促后治理预算有限的团队,建议先用开源工具自建一套最小归档流程,再针对顽固慢SQL购买单次专项优化服务,这样比全包给外部团队更省钱,也保留了内部知识沉淀。
大促后慢SQL集中治理与归档方案常见疑问
问:大促后慢SQL治理应该先优化SQL还是先归档历史数据?
答:先归档历史数据,大促后表体积膨胀是主要矛盾,归档能让主表迅速缩小,多数慢SQL不优化也会回归正常,之后再用EXPLAIN ANALYZE优化剩余高频SQL,收益更明显。
问:电商大促后订单表归档操作方法里,pt-archiver迁移会不会锁表?
答:pt-archiver默认按主键分批抓取、批量删除,每批使用独立事务提交,不会产生长时间的整表锁,但它会占用主库的读IO和写binlog,建议在低峰期执行,并设置--limit为1000条左右控制每批压力。
问:MySQL慢查询日志优化配置中,long_query_time设置多少合适?
答:日常环境建议设置为1秒,大促期间可临时放宽到2秒以减少日志量,大促后恢复为0.5秒以便抓取更细微的慢SQL,配合log_queries_not_using_indexes开启,能同时记录未使用索引的查询,即便执行时间未超过阈值。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/635617.html


