写点什么

告别扫表风暴:百度智能云数据库带你了解 MySQL 内核级全表扫描防护机制详解

作者:科技热闻
  • 2025-09-11
    浙江
  • 本文字数:1843 字

    阅读完需:约 6 分钟

在日常数据库运维中,“扫表风暴”数次悄然而至——某条未走索引的 SQL 突然执行全表扫描,短短几分钟内吃光 IO、拖高 CPU,最终引发集群抖动甚至服务不可用。这样的事故,你是否也曾经历过?


全表扫描(Full Table Scan)是数据库查询中常见的性能杀手,尤其在数据量巨大的生产环境中,一条效率低下的 SQL 就足以引发连锁性的系统故障。为从根本上防范此类风险,百度智能云数据库在 MySQL 内核层面设计并实现了一套全表扫描动态管控机制,实现对低效 SQL 的实时检测、灵活拦截与预警记录,将运维控制权真正交到开发者以及 DBA 手中。


策略机制:双模式切换、智能管控扫描行为


百度智能云数据库通常提供如下两种策略,可通过会话级变量动态切换,例如:


拦截模式:主动阻断全表扫描类 SQL,直接报错,避免其执行,防患于未然;


告警模式:放行执行但记录详细日志,用于监控、分析或审计,做到有迹可循。


用户可根据业务时段、环境类型或运维策略,随时开关相应模式,兼顾开发灵活性与生产安全性。


核心设计:变量控制+白名单机制


通常产品会引入两个系统变量,用于控制全表扫描行为:


gaia_prevent_full_table_scans(默认 OFF):一旦开启,MySQL 将在优化阶段识别全表扫描操作并直接抛出错误 ER_TABLE_FULL_SCAN,同时中断查询。


gaia_full_table_scans_alarm_allowed(默认 ON):开启后虽不拦截执行,但会向日志中写入警告信息,说明发生全表扫描的 SQL 文本,辅助后续优化。


为保障系统内部查询不受干扰,产品内置了对系统库(如 mysql、sys、information_schema 等)的白名单支持。


实现原理:深度钩入查询执行流程


此项能力并非通过外围脚本或中间件实现,而是以内核补丁的方式深度集成在 MySQL 查询执行流程中,例如在 Query_expression::execute()阶段新增扫描检查逻辑,优化完成后检查执行计划调用 check_full_table_scan()判断当前 SQL 是否包含全表扫描。


其中拦截逻辑是这样的:


如果 gaia_prevent_full_table_scans=ON 且存在全表扫描:


抛出 ER_TABLE_FULL_SCAN 错误;


中断执行


告警逻辑则是这样的:


如果 gaia_full_table_scans_alarm_allowed=ON 且存在全表扫描:


在日志打印 WARNING 信息,记录 SQL;


增加计数器 table_full_scan_count。


正常执行的情况如下,如果未命中限制条件则正常走执行 ExecuteIteratorQuery(thd)。


在 check_full_table_scan()中:


遍历 JOIN 的 qep_tab 执行计划;


判断 qep_tab->type()是否为 JT_ALL(全表扫描);


若表属于白名单数据库,则跳过检查;


其他情况则标记 has_full_table_scan=true。


伪代码示例:


switch (qep_tab->type()) {


case JT_ALL:


if (非系统数据库) {



}


break;


default:


// 非全表扫描


has_full_table_scan = false;


}


使用示例:明快的控制体验


开启拦截模式,如下:


// 将拦截模式开关打开。


SET SESSION gaia_prevent_full_table_scans =ON;


// 查询一个全表扫描的语句。


SELECT * FROM t1;


// 查询会被拦截,并且报错。


--ERROR 12345 (HY000): There is a full table scan in sql. You can modify gaia_prevent_full_table_scans to turn off the restriction


图片 1.jpg


启用告警模式,如下:


// 关闭拦截模式,并且打开报警开关。


SET SESSION gaia_prevent_full_table_scans = OFF;


SET SESSION gaia_full_table_scans_alarm_allowed =ON;


// 查询一个全表扫描的语句。


SELECT * FROM t1;


// 查询可以正常执行,但是会在日志中,打印涉及全表扫描的 sql。


-- SQL 正常执行-- 日志打印: WARNING [Full table scan sql : SELECT * FROM t1;]



测试表现:精准识别、稳定可控


我们对该机制进行了多场景验证,分别是:


正常索引查询畅通无阻;全表扫描在拦截模式下准确中断。


设置 gaia_prevent_full_table_scans=ON,执行全表扫描 SQL,确认报错;


设置 gaia_full_table_scans_alarm_allowed=ON,确认日志输出但 SQL 可执行。


系统库查询不受影响。


在 mysql 数据库执行 SELECT * FROM user;,确认不会报错。


双变量冲突时以拦截为优先策略,避免安全漏洞。


两个变量都 OFF 时,全表扫描允许执行且不告警;


两个变量都 ON 时,以 prevent 优先。


总结:运维新利器、性能守护者


这套全表扫描限制机制虽在实现上简洁高效,却可为数据库系统带来立竿见影的收益:


事前预防:拦截模式将风险查询拒之门外,保障生产环境稳定;


事中可见:告警模式记录低效 SQL,便于跟踪与优化;


灵活调度:动态开关策略,适配不同业务时段与环境类型;


无缝集成:内核级实现,无需修改业务 SQL,零侵入。


对于具备中大规模 MySQL 集群的企业来说,这类细粒度、内核级的管控工具,无疑是提升数据库可靠性与运维效率的关键一步。

用户头像

科技热闻

关注

还未添加个人签名 2021-05-31 加入

还未添加个人简介

评论

发布
暂无评论
告别扫表风暴:百度智能云数据库带你了解MySQL内核级全表扫描防护机制详解_科技热闻_InfoQ写作社区