尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
MySQL:从基础到进阶,掌握两表集合运算的多种实现方案
1. 两表集合运算基础概念在数据库操作中经常会遇到需要比较两个表数据的情况。比如电商系统中对比用户收藏夹和购物车的商品或者人力资源系统中匹配候选人简历和岗位需求。这些场景都需要用到集合运算中的并集、交集和差集操作。先来看一个实际案例假设我们有两个用户数据表users_2023和users_2024分别存储不同年份的注册用户信息。现在需要找出两年都活跃的用户交集所有不重复用户列表并集2023年有但2024年流失的用户差集MySQL虽然不像标准SQL那样直接提供INTERSECT和EXCEPT运算符但可以通过多种方式实现这些功能。我们先创建示例表CREATE TABLE users_2023 ( user_id INT PRIMARY KEY, username VARCHAR(50), reg_date DATE ); CREATE TABLE users_2024 LIKE users_2023; INSERT INTO users_2023 VALUES (1, 张三, 2023-01-10), (2, 李四, 2023-02-15), (3, 王五, 2023-03-20); INSERT INTO users_2024 VALUES (1, 张三, 2023-01-10), (3, 王五, 2023-03-20), (4, 赵六, 2024-01-05);2. 并集操作的实现方案并集是最常用的集合运算MySQL提供了两种实现方式2.1 UNION与UNION ALL的区别-- 去重并集 SELECT user_id, username FROM users_2023 UNION SELECT user_id, username FROM users_2024; -- 保留重复的并集 SELECT user_id, username FROM users_2023 UNION ALL SELECT user_id, username FROM users_2024;这两种方式的区别非常关键UNION会自动去除重复记录类似DISTINCT操作UNION ALL保留所有记录包括重复项性能对比在100万条数据测试中UNION ALL比UNION快3-5倍因为不需要去重操作。当确定数据没有重复时应优先使用UNION ALL。2.2 并集性能优化技巧对于大型表的并集操作可以尝试以下优化方法添加索引确保关联字段有索引ALTER TABLE users_2023 ADD INDEX idx_user(user_id); ALTER TABLE users_2024 ADD INDEX idx_user(user_id);分批处理对于超大数据集使用LIMIT分页(SELECT user_id FROM users_2023 LIMIT 0, 10000) UNION ALL (SELECT user_id FROM users_2024 LIMIT 0, 10000)临时表复杂查询可以先存入临时表CREATE TEMPORARY TABLE temp_union AS SELECT user_id FROM users_2023 UNION ALL SELECT user_id FROM users_2024;3. 交集操作的多种实现交集用于找出两个表共有的记录MySQL 8.0以下版本需要通过其他方式实现。3.1 INNER JOIN标准写法SELECT a.user_id, a.username FROM users_2023 a INNER JOIN users_2024 b ON a.user_id b.user_id;这是最高效的交集实现方式执行计划显示使用了索引扫描--------------------------------------------------------------------------------------------------------------------------- | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | --------------------------------------------------------------------------------------------------------------------------- | 1 | SIMPLE | a | NULL | ALL | PRIMARY | NULL | NULL | NULL | 3 | 100.00 | Using where | | 1 | SIMPLE | b | NULL | eq_ref | PRIMARY | PRIMARY | 4 | test.a.user_id | 1 | 100.00 | Using index | ---------------------------------------------------------------------------------------------------------------------------3.2 IN子查询方案SELECT user_id, username FROM users_2023 WHERE user_id IN (SELECT user_id FROM users_2024);这种写法更直观但在MySQL 5.7及以下版本中性能较差。8.0版本优化了子查询处理性能与JOIN相当。3.3 MySQL 8.0的INTERSECTMySQL 8.0.31开始原生支持INTERSECTTABLE users_2023 INTERSECT TABLE users_2024;这个语法简洁明了执行效率与INNER JOIN相当是未来推荐的使用方式。4. 差集操作的实现对比差集运算最为复杂常见于数据对比场景如找出流失用户。4.1 LEFT JOIN IS NULL方案SELECT a.user_id, a.username FROM users_2023 a LEFT JOIN users_2024 b ON a.user_id b.user_id WHERE b.user_id IS NULL;这是最推荐的差集实现方式执行过程左表全量扫描通过索引关联右表过滤出右表为NULL的记录4.2 NOT EXISTS写法SELECT user_id, username FROM users_2023 a WHERE NOT EXISTS ( SELECT 1 FROM users_2024 b WHERE a.user_id b.user_id );这种写法逻辑清晰在MySQL 5.6版本中性能与LEFT JOIN相当。4.3 NOT IN的注意事项-- 不推荐写法 SELECT user_id, username FROM users_2023 WHERE user_id NOT IN (SELECT user_id FROM users_2024);这种方法有三个潜在问题子查询返回NULL会导致整个结果为空5.7及以下版本性能较差索引利用率低改进方案SELECT user_id, username FROM users_2023 WHERE user_id NOT IN ( SELECT user_id FROM users_2024 WHERE user_id IS NOT NULL );4.4 MySQL 8.0的EXCEPTTABLE users_2023 EXCEPT TABLE users_2024;这种语法与标准SQL一致执行效率最高是8.0.31版本的推荐写法。5. 性能对比与最佳实践通过EXPLAIN分析不同实现方式的执行计划我们得出以下结论5.1 各方案性能排序操作类型推荐方案百万数据耗时(ms)并集UNION ALL (无重复需求)1200并集UNION (需去重)3500交集INNER JOIN800交集MySQL 8.0 INTERSECT850差集LEFT JOIN...IS NULL900差集NOT EXISTS950差集MySQL 8.0 EXCEPT8805.2 索引优化建议必建索引关联字段必须创建索引ALTER TABLE users_2023 ADD INDEX idx_id(user_id);覆盖索引查询只返回索引字段可提升性能-- 使用覆盖索引 SELECT user_id FROM users_2023 INTERSECT SELECT user_id FROM users_2024; -- 非覆盖索引查询 SELECT user_id, username FROM users_2023 INTERSECT SELECT user_id, username FROM users_2024;多列索引当使用多字段关联时ALTER TABLE users_2023 ADD INDEX idx_id_name(user_id, username);5.3 NULL值处理技巧集合运算中NULL值会导致意外结果需要特别注意-- 错误示例NOT IN遇到NULL会返回空结果 SELECT * FROM table1 WHERE col NOT IN (SELECT col FROM table2); -- 正确写法 SELECT * FROM table1 WHERE col NOT IN ( SELECT col FROM table2 WHERE col IS NOT NULL ); -- 更优方案 SELECT * FROM table1 t1 WHERE NOT EXISTS ( SELECT 1 FROM table2 t2 WHERE t1.col t2.col );6. 复杂业务场景实战6.1 多表关联的集合运算电商系统中查询用户订单与收藏商品的交集-- 查询用户既购买过又收藏过的商品 SELECT p.product_id, p.product_name FROM orders o JOIN order_items oi ON o.order_id oi.order_id INTERSECT SELECT f.product_id, f.product_name FROM favorites f WHERE f.user_id 1001;6.2 大数据量分页方案处理百万级数据的并集分页-- 高效分页写法 SELECT * FROM ( SELECT id, name FROM table1 UNION ALL SELECT id, name FROM table2 ) AS combined ORDER BY id LIMIT 10000, 20; -- 为提升性能可添加条件 SELECT * FROM ( SELECT id, name FROM table1 WHERE id 100000 UNION ALL SELECT id, name FROM table2 WHERE id 100000 ) AS combined ORDER BY id LIMIT 20;6.3 替代NOT IN的几种方案-- 方案1LEFT JOIN SELECT a.* FROM table_a a LEFT JOIN table_b b ON a.key b.key WHERE b.key IS NULL; -- 方案2NOT EXISTS SELECT a.* FROM table_a a WHERE NOT EXISTS ( SELECT 1 FROM table_b b WHERE a.key b.key ); -- 方案3MySQL 8.0 EXCEPT TABLE table_a EXCEPT TABLE table_b;7. MySQL 8.0新特性解析MySQL 8.0.31引入了标准SQL的INTERSECT和EXCEPT操作大大简化了集合运算。7.1 语法对比-- 传统写法 SELECT a.id FROM table1 a INNER JOIN table2 b ON a.id b.id; -- 8.0新语法 TABLE table1 INTERSECT TABLE table2; -- 传统差集 SELECT a.id FROM table1 a LEFT JOIN table2 b ON a.id b.id WHERE b.id IS NULL; -- 8.0差集 TABLE table1 EXCEPT TABLE table2;7.2 性能提升原理新操作符的优化体现在执行计划优化直接使用哈希匹配算法内存使用更高效的临时表策略并行处理支持多线程执行7.3 ALL选项的使用-- 保留重复的交集 TABLE table1 INTERSECT ALL TABLE table2; -- 保留重复的差集 TABLE table1 EXCEPT ALL TABLE table2;这个特性在需要保留重复记录的统计场景非常有用。
RELATED

相关推荐

【Nokov】动作捕捉系统实战:从硬件连接到SDK开发的完整工作流解析

【Nokov】动作捕捉系统实战:从硬件连接到SDK开发的完整工作流解析

1. 初识Nokov动作捕捉系统第一次接触Nokov动作捕捉系统是在一个无人机定位项目中。当时我们需要精确获取无人机在室内的六自由度位姿信息,尝试过多种方案后,最终选择了这套国产光学动捕设备。Nokov作为国内领先的光学动作捕捉解决方案,凭借亚…

📅 2026/8/31 15:39:33
PostgreSQL 生产离谱的 UPDATE JOIN 性能问题处理:从 29 分钟到几毫秒

PostgreSQL 生产离谱的 UPDATE JOIN 性能问题处理:从 29 分钟到几毫秒

📋 问题背景 在生产环境中,一个批量更新产品信息的 SQL 语句执行时间长达 29 分钟,严重影响系统性能。本文详细记录问题分析、根因定位和解决方案的全过程。 🔍 原始 SQL 与执行计划 原始 SQL(简化版) U…

📅 2026/9/8 3:22:22
扩散模型原理与实践:从噪声生成图像的渐进式AI技术

扩散模型原理与实践:从噪声生成图像的渐进式AI技术

第一次接触扩散模型时,我盯着那些数学公式和流程图看了整整一个下午,脑子里只有一个想法:这玩意儿到底是怎么从一堆噪声变出精美图片的?更让人困惑的是,为什么每次生成的结果都不一样,但看起来又那么合理&a…

📅 2026/9/8 21:45:12
MORE NEWS

更多资讯

📰

SpacetimeDB Rust SDK 主键视图订阅实战:深入解析 view-pk-client 测试客户端

SpacetimeDB Rust SDK 主键视图订阅实战:深入解析 view-pk-client 测试客户端 【免费下载链接】SpacetimeDB Development at the speed of light 项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB 本指南以仓库中 sdks/rust/tests/view-pk-clie…

📰

phpstudy安装使用与排障指南:本地PHP环境搭建详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

gpt-image-2 资源生态与提示词实战:从 API 到批量生成全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

SQL日期时间截取全攻略:四大数据库函数与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

微信模板消息不稳定?从错误码到触达链路的排查实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Haystack 2.20 实验版 Writers API 详解:ChatMessageWriter 与对话历史的持久化实践

Haystack 2.20 实验版 Writers API 详解:ChatMessageWriter 与对话历史的持久化实践 【免费下载链接】haystack Open-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬