
【MySQL 笔记】复合查询Compound Queries / Set Operations详解在 MySQL 中“复合查询”一词在不同语境下有两种常见含义广义任何把多个查询逻辑组合起来的查询JOIN 子查询 集合运算等狭义最常指集合运算Set Operations即用UNION、INTERSECT、EXCEPT等把多个 SELECT 的结果集进行并、交、差操作今天我们重点讲狭义的复合查询——集合运算MySQL 8.0 已完整支持这是面试和数据分析中非常高频的内容。一、MySQL 集合运算符对比表2026 年现状运算符含义是否去重MySQL 支持版本结果特点典型场景UNION并集是所有版本去重后合并合并同类数据如历史表新表UNION ALL并集不去重否所有版本保留所有重复行性能最好日志合并、报表数据累加INTERSECT交集是8.0.31只保留两边都出现的行找出同时满足 A 和 B 条件的数据INTERSECT ALL交集保留重复否8.0.31保留最小重复次数极少用精确重复计数场景EXCEPT差集A - B是8.0.31只保留出现在 A、不在 B 的行找出只在 A 表有的记录差异对比EXCEPT ALL差集不去重否8.0.31减去对应重复次数精确多对多差集注意MySQL 8.0.31 之前只有UNION/UNION ALLINTERSECT和EXCEPT是 8.0.312022 年 10 月才正式加入的。二、基本语法结构SELECTcolumn_listFROMtable1[WHERE...]UNION[ALL|DISTINCT]SELECTcolumn_listFROMtable2[WHERE...][ORDERBY...][LIMIT...];多个 SELECT 的列数必须相同列的数据类型要兼容可隐式转换列名以第一个 SELECT为准ORDER BY和LIMIT只能出现在最后整个复合查询的末尾三、实战示例表建议自己建表跑-- 用户表 A老数据CREATETABLEusers_old(idINTPRIMARYKEY,nameVARCHAR(20),cityVARCHAR(20));INSERTINTOusers_oldVALUES(1,张三,北京),(2,李四,上海),(3,王五,广州),(4,赵六,北京);-- 用户表 B新数据CREATETABLEusers_new(idINTPRIMARYKEY,nameVARCHAR(20),cityVARCHAR(20));INSERTINTOusers_newVALUES(3,王五,深圳),(4,赵六,北京),(5,孙七,成都),(6,周八,杭州);四、各种复合查询演示-- 1. UNION去重并集SELECTname,cityFROMusers_oldUNIONSELECTname,cityFROMusers_new;-- 结果张三北京、李四上海、王五深圳、赵六北京、孙七成都、周八杭州-- 王五和赵六只出现一次-- 2. UNION ALL不去重推荐性能更好SELECTname,cityFROMusers_oldUNIONALLSELECTname,cityFROMusers_new;-- 结果8 行王五和赵六各出现两次-- 3. INTERSECT交集找出两表都有的用户SELECTname,cityFROMusers_oldINTERSECTSELECTname,cityFROMusers_new;-- 结果赵六 北京因为 city 也必须完全相同-- 如果只比 id可先 SELECT id-- 4. EXCEPT差集老表有、新表没有的SELECTname,cityFROMusers_oldEXCEPTSELECTname,cityFROMusers_new;-- 结果张三 北京、李四 上海、王五 广州-- 5. 复杂组合 排序常用于分页报表(SELECTname,city,oldASsourceFROMusers_old)UNIONALL(SELECTname,city,newASsourceFROMusers_new)ORDERBYnameLIMIT5;-- 6. 找出“只在新表出现”的用户新用户SELECTname,cityFROMusers_newEXCEPTSELECTname,cityFROMusers_old;-- 结果孙七 成都、周八 杭州五、高频使用场景总结面试实战场景推荐写法为什么推荐历史表 当月表 合并报表UNION ALL不想去重数据量大时性能关键全量用户列表去重UNION天然去重找出新增用户新表EXCEPT老表清晰、直观找出共同活跃用户INTERSECT8.0.31 直接写很优雅数据对账 / 差异比对EXCEPTUNION组合快速定位只在一边的记录多数据源合并日志、爬虫等UNION ALL source 列保留原始记录 标记来源六、性能 注意事项2026 年视角UNION ALL UNION不去重性能远高于去重去重需要排序判重列数 类型必须一致否则报错The used SELECT statements have a different number of columnsORDER BY 放最后且只能用列序号或第一个 SELECT 的列别名...UNION...ORDERBY1DESC;-- 第一列索引利用每个 SELECT 单独优化复合后整体优化有限替代方案老版本或性能敏感时交集 →INNER JOIN或EXISTS差集 →LEFT JOIN ... WHERE right.id IS NULL但 8.0.31 后INTERSECT/EXCEPT可读性更好下一期预告建议MySQL 子查询Subquery全家桶 相关子查询 vs 非相关 性能对比有复合查询写法特别头疼的业务场景比如多表合并去重、分库分表后聚合等欢迎留言我们一起分析祝大家复合查询写得又稳又快