mysql集合查询适合什么场景_mysql使用建议说明

7次阅读

必须用 UNION 而非多次 SELECT 的核心场景是结果集结构一致且业务逻辑属同一类数据不同来源,如分库分表查活跃用户或合并订单状态表;需严格对齐字段顺序与类型,去重需求明确时才用 UNION,否则优先 UNION ALL 以避免隐式排序与去重开销。

mysql 集合查询适合什么场景_mysql 使用建议说明

MySQL 集合查询(UNIONUNION ALLINTERSECTEXCEPT)不是万能的去重或合并 工具,用错场景反而拖慢查询、掩盖数据问题。

什么时候必须用 UNION 而不是多次 SELECT

核心判断点:结果集结构一致,且业务逻辑上属于「同一类数据的不同来源」。

  • 用户表分库分表后需统一查活跃用户:SELECT id, name FROM user_shard_1 WHERE last_login > '2024-01-01' UNION SELECT id, name FROM user_shard_2 WHERE last_login > '2024-01-01'
  • 订单状态分散在不同表(如 order_normalorder_refund),但 前端 需要统一列表展示,字段顺序和类型必须严格对齐
  • UNION 会自动去重并排序,如果不需要去重,务必改用 UNION ALL,否则隐式 DISTINCT + ORDER BY 开销极大
  • MySQL 8.0.19+ 才原生支持 INTERSECTEXCEPT,低版本得用 INNER JOINNOT EXISTS 模拟,别硬套语法

UNION ALL 性能比 UNION 高多少?

不是“高一点”,而是量级差异——尤其在百万级以上结果集。

  • UNION 内部等价于 UNION ALL + GROUP BY(或临时表去重),涉及磁盘临时表、排序、哈希计算
  • UNION ALL 只做结果集拼接,无额外逻辑,执行计划里看不到 Using temporary; Using filesort
  • 实测:两个各返回 50 万行的子查询,UNION ALL 耗时约 0.12s;UNION 耗时 1.8s 以上(取决于内存配置)
  • 如果业务允许重复(比如日志归集、埋点上报合并),默认选 UNION ALL;去重要求必须明确来自业务,而非“怕出错就用 UNION”

字段类型不一致导致 UNION 报错或 隐式转换

MySQL 对 UNION 各子句的列类型兼容性很敏感,报错往往不直观。

  • 常见错误:ERROR 1267 (HY000): Illegal mix of collations —— 字符集 / 校对规则不一致,比如 utf8mb4_0900_as_csutf8mb4_general_ci 混用
  • INTVARCHAR 同列位置会触发隐式转换,可能截断或转成 0,例如:SELECT 123 UNION SELECT 'abc' → 第二列转成 123(字符串转数字失败则为 0)
  • 解决方法:显式 CASTCONVERT 统一类型,例如:SELECT CAST(id AS CHAR) FROM t1 UNION SELECT name FROM t2
  • 列别名只取第一个子句的,后续子句别名无效,别指望靠别名对齐字段语义

替代方案比 UNION 更合适的情况

集合操作是语法糖,不是性能银弹。很多场景用单表 JOIN 或应用层聚合更稳。

  • 要查「A 表有但 B 表没有」的数据,优先写 LEFT JOIN …… WHERE b.id IS NULL,比 SELECT …… EXCEPT SELECT …… 兼容性好、执行计划更可控
  • 多条件动态组合查询(比如搜索页的「价格区间 + 品类 + 标签」),用 OR / IN / 条件拼接通常比多个 UNION 快,且便于加索引
  • 子查询结果集很小(UNION 涉及 5 张表,不如应用层拉回内存做集合运算,避免 MySQL 多次全表扫描
  • UNION 无法下推谓词(WHERE 条件不能下压到每个子查询内部优化),而单独写多个 SELECT 可分别走索引
SELECT id, title FROM news WHERE status = 1 AND created_at > '2024-01-01' UNION ALL SELECT id, title FROM articles WHERE status = 2 AND created_at > '2024-01-01';

真正麻烦的不是语法,是字段对齐、类型收敛、执行计划不可控这三件事。线上跑着的 UNION 查询,建议用 EXPLAIN FORMAT=TREE 看是否用了临时表——如果看到 materialize,基本就是性能隐患了。

text=ZqhQzanResources