网站Logo Ilren 小记

MySQL Bug #110104 实战排查:为什么 UNION + 中文 LIKE 查不出结果?

jack
26
2023-09-14

引言

最近帮同事排查了一个诡异的数据库问题,原本以为只是 SQL 写法或者字符集的锅,没想到竟然是 MySQL 官方确认的 Bug(编号 #110104

而且这个 Bug 很隐蔽:只有在 使用 UNION 合并查询 + WHERE 条件中包含中文字符 时才会触发。幸运的是,官方给出了明确的临时解决方案,并在 8.0.33 中修复了。

这篇文章分享整个排查过程,希望你也能少走弯路。

问题现象

同事给我发来一段 SQL:

SELECT * FROM (
    SELECT id, customer_name FROM order_202401
    UNION
    SELECT id, customer_name FROM order_202402
) AS tmp
WHERE customer_name LIKE '%张三%';

他说:“明明库里有叫张三的记录,结果查出来是空的,但把张三改成 zhangsan 又能查出来。”

我第一反应是字符集问题,但深入一查,才发现是个更深的坑。

排查过程

我们按以下思路一一排查:

  1. ✅ 表的字符集:都是 utf8mb4

  2. ✅ 字段类型:customer_name 是标准 varchar

  3. EXPLAIN 执行计划没看出什么异常

  4. ✅ 不使用 UNION 就能正常查出中文

然后我们尝试将查询改成只查一个表:

SELECT * FROM order_202401 WHERE customer_name LIKE '%张三%'; 

✅ 可以查出来!

但只要套上 UNION 和子查询,再加上中文 LIKE 条件,就查不到了……

此时我基本可以断定,是查询优化器在处理 UNION + 派生表 + 中文 WHERE 时出了问题。

最终定位:MySQL Bug #110104

我们在 MySQL 官方 Bug 跟踪平台 上搜到了一个非常符合的条目:

Bug #110104 - In 8.0.32, the matching query of Chinese characters is included, and the result set is incorrect.

简而言之:

  • 只要用 UNION 合并多个子查询

  • 再用 WHERE 加上中文条件过滤派生表

  • 就可能会导致查询失效(结果为空)

官方修复与解决方案

  • 修复版本:MySQL 8.0.33

  • 临时解决方案:关闭 derived_condition_pushdown 优化器

-- 会话级别关闭(推荐)
SET SESSION optimizer_switch='derived_condition_pushdown=off';

-- 或全局关闭(需管理员权限)
SET GLOBAL optimizer_switch='derived_condition_pushdown=off';

一行指令,问题立刻解决!中文能查出来了!

示例对比

-- 失败示例(开启 derived_condition_pushdown 时)
SELECT * FROM (
    SELECT id, name FROM user_2023
    UNION
    SELECT id, name FROM user_2024
) AS u
WHERE name LIKE '%李四%';
-- 返回空结果 ❌

-- 成功示例(关闭 derived_condition_pushdown)
SET SESSION optimizer_switch='derived_condition_pushdown=off';

SELECT * FROM (
    SELECT id, name FROM user_2023
    UNION
    SELECT id, name FROM user_2024
) AS u
WHERE name LIKE '%李四%';
-- 正常返回结果 ✅

什么是 derived_condition_pushdown?

这是 MySQL 优化器的一个选项:

如果开启,MySQL 会尝试将外层 WHERE 条件下推到子查询内部,提高查询效率。

但在某些情况下(尤其涉及中文字符匹配时),这个优化会错误地处理条件,导致本不该过滤掉的数据被排除。

总结

项目

内容

问题现象

UNION 联表查询 + WHERE 中文条件,查不到数据

官方 Bug

✅ Bug #110104

影响版本

MySQL 8.0.32

修复版本

✅ 8.0.33

临时方案

SET optimizer_switch='derived_condition_pushdown=off'

根本方案

升级到 MySQL 8.0.33 或以上

开发建议

  • 如果你使用的是 MySQL 8.0.32 且有复杂 SQL 查询(尤其涉及 UNION、中文 LIKE、子查询等),建议检查是否触发该 Bug。

  • 临时解决方案靠谱,但长期建议尽快升级数据库。

最后

这次帮同事排查的经历让我再次意识到:

不是所有奇怪的行为都是你代码的问题,也可能是数据库自己翻车了。

动物装饰