问题描述
在 MySQL 8.0.32 版本中,当使用 UNION 操作将多个 SELECT 语句的结果合并,并在 WHERE 条件中使用中文字符进行过滤时,可能会出现无法查询到预期结果的问题。
现象
比如一个视图是这样定义的:
select col1, col2 from table_a union select col1, col2 from table_b;
然后查询视图(假设视图名称为view_a):select * form view_a 是有数据的且包含col=中文1'的数据,但是select * from col1='中文1' 就是没有数据!
- 查询结果不正确: 即使数据库中存在符合条件的数据,查询结果也为空或不完整。
原因分析
- MySQL 优化器问题: 在处理 UNION 操作和 WHERE 条件结合时,MySQL 优化器可能会对中文字符的处理存在一些问题,导致条件判断错误。
解决办法
1. 升级 MySQL 版本
- 最直接有效的方法: MySQL 官方已经修复了这个 bug,建议升级到 8.0.33 或更高版本。
2. 调整优化器开关
- 临时解决方案: 如果无法立即升级,可以尝试关闭
derived_condition_pushdown
优化器开关:SQLSET GLOBAL optimizer_switch='derived_condition_pushdown=off';
注意: 关闭这个开关可能会影响其他查询的性能。
3. 重写 SQL 语句
- 避免 UNION 操作: 尝试使用 LEFT JOIN 或其他方式替代 UNION 操作,简化查询逻辑。
- 使用 COALESCE 函数: 处理不同来源的字段,避免 NULL 值导致的问题。
- 调整 WHERE 条件: 将 WHERE 条件放在子查询中,或者使用 CASE WHEN 表达式。
4. 检查字符集和排序规则
- 确保一致性: 数据库、表和字段的字符集和排序规则应保持一致,通常建议使用 UTF-8 字符集。
5. 创建索引
- 提高查询效率: 为经常用于过滤的字段创建索引,可以加速查询。
示例:重写 SQL 语句
SQL
SELECT
t1.id AS id,
COALESCE(t2.id, NULL) AS material_id,
-- ...其他字段
FROM
t_component_item t1
LEFT JOIN
t_material t2 ON t1.material_no = t2.no
WHERE COALESCE(t2.source, t1.source) = '调拨';
总结
MySQL 8.0.32 中存在一个与 UNION 操作和 WHERE 条件结合时处理中文字符相关的 bug,导致查询结果不正确。升级 MySQL 版本是解决问题的最根本方法。如果无法升级,可以通过调整优化器开关、重写 SQL 语句、检查字符集等方式进行临时解决。
文章评论