优化mysql中or查询的核心是确保每个分支独立走索引,首选union all拆分;同字段等值or应改用in;须避免函数、隐式转换及复合索引不满足最左前缀等问题。

Java 中调用 MySQL 查询时,OR 条件本身不会因为 Java 层写法而变快,真正起决定作用的是 SQL 执行计划是否走索引。优化核心在于:让 MySQL 优化器能对每个 OR 分支独立使用索引,而不是放弃索引、全表扫描。Java 层只需确保传入的 SQL 是可优化的,并配合 EXPLAIN 验证效果。
优先用 UNION ALL 拆分 OR 分支
这是最稳定、兼容性最好、效果最可控的方式——把一个含 OR 的查询,改写成多个子查询,各自命中对应字段的索引,再合并结果。
- 必须用 UNION ALL,不是 UNION:后者会自动去重 + 排序,触发临时表和文件排序,大数据量时明显更慢
- 每个子查询 WHERE 条件只保留本分支字段的过滤逻辑,例如
status = 'paid'或city = 'Shanghai',不要混入其他条件 - 所有子查询 SELECT 的列数、顺序、类型、NULL 属性必须完全一致,否则 MySQL 直接报错
ERROR 1222 - 如果原 SQL 有
ORDER BY ... LIMIT 10,不能只在外层加;应先在每个子查询里按需估算上界(如LIMIT 10),再外层统一排序分页,否则可能漏数据
确保每个分支都有可用索引
UNION ALL 能生效的前提是:每个子查询都能独立走索引。光有索引还不够,得验证它真被用了。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 对每个分支单独执行
EXPLAIN SELECT ... WHERE field = ?,确认type是ref或range,key显示索引名,rows明显小于总行数 - 若字段无索引,直接加:比如
ALTER TABLE users ADD INDEX idx_city (city) - 避免一边有索引、另一边没索引:例如
name = ? OR remark LIKE '%abc%',后半部分必然无法走索引,整个 OR 就大概率退化为全表扫描
同字段多值 OR 直接换成 IN
当 OR 全部作用于同一个字段的等值判断时,不用 UNION,MySQL 对 IN 的优化很成熟,仍能高效走索引。
- 例如
status = 1 OR status = 2 OR status = 3→ 改为status IN (1, 2, 3) - IN 值数量建议控制在几百以内;过多会导致解析开销上升,某些版本可能触发临时表
- 注意语义差异:
col IN (1, NULL)不匹配 NULL 行,而col = 1 OR col IS NULL会匹配,不能无脑替换
避开常见陷阱
有些看似合理的写法,实际会让索引“隐身”。
- OR 中混入函数或表达式:如
UPPER(name) = 'ALICE' OR city = 'Beijing',前半部分无法走索引 - 隐式类型转换:如字符串字段
phone存的是'13812345678',却写成phone = 13812345678,触发转换,索引失效 - 复合索引未满足最左前缀:比如索引是
(a, b),但写成a = 1 OR b = 2,无法利用该复合索引 - 一边是
IS NULL,一边是等值:如email = 'a@b.com' OR email IS NULL,即使有索引也大概率不走
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










