能,但仅对非预处理的SELECT语句生效;重写发生在解析后、优化前,通过正则匹配替换AST中的SELECT子句,不支持DML、存储过程及动态拼接SQL。

MySQL 8.0+ 重写插件是否真能改第三方系统的慢 SQL?
能,但只对 SELECT 语句生效,且必须走查询解析器(即不能是预处理语句绑定后动态拼的 SQL)。重写插件本质是在 SQL 解析后、优化器开始前,用正则匹配并替换 AST 中的 SELECT 子句——它不碰 INSERT、UPDATE、DELETE,也不改存储过程或触发器里的 SQL。
常见误判点:以为开启插件就能“自动加速所有慢查”,结果发现 SHOW PROFILES 里耗时没变。原因往往是第三方系统用 PREPARE + EXECUTE 方式执行 SQL,而重写插件默认不处理这类语句(需显式设置 query_rewrite_enabled=ON 并确认 performance_schema 中的 prepared_statements_instances 表未被绕过)。
怎么写一条安全有效的重写规则?
核心原则:只重写明确可推导、无副作用的子查询或 JOIN 条件。比如把 WHERE create_time > DATE_SUB(NOW(), INTERVAL 7 DAY) 改成基于具体日期的常量,避免每次执行都调用 NOW() 导致索引失效。
- 必须用
mysql_query_rewrite.add_rewrite_rule()注册,不能直接 INSERT 到query_rewrite.rewrite_rules - 匹配模式(
pattern)要加锚点:^SELECT.*FROM orders WHERE create_time > DATE_SUB\(NOW\(\), INTERVAL 7 DAY\)$,否则可能误伤其他语句 - 替换内容(
replacement)里禁止含变量、函数或子查询;只允许字面值、列名、表别名和固定 JOIN 条件 - 规则启用后需执行
mysql_query_rewrite.flush_rewrite_rules(),否则不生效
为什么规则加了却没触发?排查三步法
最常卡在权限、作用域和语法细节上:
- 执行
SELECT * FROM performance_schema.query_rewrite_rules,确认active是YES,且pattern字段没被截断(MySQL 8.0.22 前该字段长度仅 2048 字符) - 检查目标 SQL 是否带 schema 名:如果原语句是
SELECT * FROM mydb.orders,但规则里写的FROM orders,就不会匹配——得写全FROM mydb\.orders并转义点号 - 用
EXPLAIN FORMAT=TREE对比改写前后执行计划,若输出中仍有DEPENDENT SUBQUERY或Using temporary; Using filesort,说明重写未成功或新 SQL 本身仍不优
重写规则上线后要注意哪些隐性成本?
每条规则都会增加 parser 阶段开销,尤其当 query_rewrite_rules 表里规则数 > 50 条时,简单 SELECT 的解析延迟可能从 0.02ms 升到 0.15ms。更关键的是:规则一旦匹配,原始 SQL 的 SQL_NO_CACHE、STRAIGHT_JOIN 等 hint 全部丢失,且无法回溯原始语句用于审计。
真实踩坑案例:某系统把 WHERE status IN ('pending','processing') 重写为 WHERE status = 'pending'(漏掉另一状态),上线后订单漏查——因为开发只验证了“有结果”,没验证“结果全不全”。重写不是兜底方案,它只适合逻辑确定、变更可控的局部优化。










