1. 复合查询基础概念解析MySQL中的复合查询是指通过组合多个简单查询语句构建更复杂的数据检索操作。这种查询方式在实际业务场景中极为常见特别是当我们需要从多个维度分析数据或处理关联性较强的数据集时。复合查询的核心价值在于它能够合并多个查询结果集UNION嵌套查询条件子查询组合多表关联JOIN实现分层数据筛选EXISTS/NOT EXISTS注意复合查询虽然功能强大但不当使用可能导致性能问题。在设计查询时应始终考虑执行计划和索引利用情况。我处理过的一个典型案例是电商平台的订单分析系统。当需要统计购买了A商品但未购买B商品的用户同时这些用户在过去30天内有登录行为时就必须使用复合查询组合多个条件。2. 复合查询核心类型与实现2.1 UNION联合查询UNION操作符用于合并两个或多个SELECT语句的结果集。关键特性包括默认去除重复行使用UNION ALL保留重复每个SELECT语句必须有相同数量的列列数据类型必须兼容-- 合并不同部门的员工名单 SELECT emp_name FROM sales_employees UNION SELECT emp_name FROM tech_employees;实际项目中我发现几个值得注意的点大数据量时UNION ALL性能明显优于UNION可以在最后统一排序避免中间结果排序开销MySQL 8.0支持UNION的CTE(Common Table Expressions)写法2.2 子查询实践子查询分为几种典型应用场景2.2.1 WHERE子句中的子查询-- 找出薪资高于平均薪资的员工 SELECT emp_name, salary FROM employees WHERE salary (SELECT AVG(salary) FROM employees);2.2.2 FROM子句中的派生表-- 计算各部门平均薪资并按高低排序 SELECT dept_name, avg_salary FROM ( SELECT dept_name, AVG(salary) as avg_salary FROM employees GROUP BY dept_name ) AS dept_stats ORDER BY avg_salary DESC;2.2.3 EXISTS/NOT EXISTS应用-- 找出有订单的客户 SELECT cust_name FROM customers c WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.cust_id c.cust_id );提示EXISTS在子查询返回大量数据时通常比IN更高效因为它找到第一个匹配项就会停止搜索。3. 多表连接与复合条件3.1 JOIN类型选择策略MySQL支持多种JOIN操作每种都有特定的适用场景JOIN类型特点适用场景INNER JOIN只返回匹配行需要精确匹配时LEFT JOIN返回左表全部右表匹配保留主表完整记录RIGHT JOIN返回右表全部左表匹配较少使用(通常用LEFT替代)FULL JOINMySQL不直接支持需要模拟实现CROSS JOIN笛卡尔积特定分析场景-- 典型的三表关联查询 SELECT o.order_id, c.cust_name, p.product_name FROM orders o JOIN customers c ON o.cust_id c.cust_id JOIN products p ON o.product_id p.product_id WHERE o.order_date 2023-01-01;3.2 复合WHERE条件构建合理组合WHERE条件可以显著提高查询效率-- 多条件组合查询 SELECT * FROM products WHERE category 电子产品 AND (price 1000 OR stock_count 10) AND create_time BETWEEN 2023-01-01 AND 2023-06-30 AND product_id IN ( SELECT product_id FROM hot_products WHERE is_recommended 1 );关键优化建议将高选择性条件放在前面避免在索引列上使用函数操作使用EXPLAIN分析执行计划4. 高级复合查询技巧4.1 窗口函数应用MySQL 8.0引入了强大的窗口函数-- 计算每个部门薪资排名 SELECT emp_name, dept_name, salary, RANK() OVER (PARTITION BY dept_name ORDER BY salary DESC) as dept_rank FROM employees;4.2 递归CTE处理层级数据-- 组织结构层级查询 WITH RECURSIVE org_hierarchy AS ( -- 基础查询(顶级节点) SELECT id, name, parent_id, 1 AS level FROM organization WHERE parent_id IS NULL UNION ALL -- 递归查询 SELECT o.id, o.name, o.parent_id, h.level 1 FROM organization o JOIN org_hierarchy h ON o.parent_id h.id ) SELECT * FROM org_hierarchy;4.3 JSON数据查询现代MySQL版本支持JSON字段的高效查询-- 查询JSON字段中的特定属性 SELECT product_id, product_name, JSON_EXTRACT(specs, $.weight) AS product_weight FROM products WHERE JSON_CONTAINS(specs-$.tags, 新品);5. 性能优化与问题排查5.1 复合查询执行计划分析使用EXPLAIN解读查询性能EXPLAIN FORMATJSON SELECT * FROM orders o JOIN customers c ON o.cust_id c.cust_id WHERE o.order_date 2023-01-01 ORDER BY o.order_amount DESC;重点关注访问类型(type列)最好达到ref或range级别可能的键(possible_keys)确保使用了合适索引行数估算(rows)检查是否与预期相符5.2 常见性能问题与解决方案临时表过大症状Using temporary出现在EXPLAIN结果中解决方案优化ORDER BY/GROUP BY子句增加适当索引文件排序症状Using filesort解决方案为排序字段添加索引或调整查询结构嵌套循环过深症状大量嵌套子查询导致性能下降解决方案改用JOIN或临时表重构查询5.3 索引设计策略针对复合查询的特殊索引考虑多列索引顺序原则高选择性列在前等值查询列在前范围查询列在后排序字段尽量包含在索引中覆盖索引技巧-- 创建包含查询所需全部字段的索引 ALTER TABLE orders ADD INDEX idx_cover (cust_id, order_date, order_amount);函数索引(MySQL 8.0)-- 为JSON字段创建函数索引 ALTER TABLE products ADD INDEX idx_weight ((CAST(specs-$.weight AS DECIMAL(10,2))));6. 实际案例解析6.1 电商平台销售分析-- 分析高价值客户的购买行为 WITH customer_stats AS ( SELECT c.cust_id, c.cust_name, COUNT(o.order_id) AS order_count, SUM(o.order_amount) AS total_spent FROM customers c LEFT JOIN orders o ON c.cust_id o.cust_id GROUP BY c.cust_id, c.cust_name ) SELECT cs.*, p.product_name AS top_product FROM customer_stats cs JOIN ( SELECT o.cust_id, oi.product_id, COUNT(*) AS purchase_count, RANK() OVER (PARTITION BY o.cust_id ORDER BY COUNT(*) DESC) AS rnk FROM orders o JOIN order_items oi ON o.order_id oi.order_id GROUP BY o.cust_id, oi.product_id ) AS top_products ON cs.cust_id top_products.cust_id AND top_products.rnk 1 JOIN products p ON top_products.product_id p.product_id WHERE cs.total_spent 10000 ORDER BY cs.total_spent DESC;6.2 社交网络关系分析-- 查找共同好友 SELECT u1.user_name AS user1, u2.user_name AS user2, COUNT(DISTINCT f1.friend_id) AS common_friends_count FROM users u1 JOIN users u2 ON u1.user_id u2.user_id JOIN friendships f1 ON u1.user_id f1.user_id JOIN friendships f2 ON u2.user_id f2.user_id AND f1.friend_id f2.friend_id GROUP BY u1.user_id, u2.user_id HAVING COUNT(DISTINCT f1.friend_id) 5 ORDER BY common_friends_count DESC;7. 最佳实践与经验总结查询结构优化优先使用JOIN而非子查询MySQL 5.7对子查询优化有改进将过滤条件尽量下推到最内层查询避免在WHERE子句中对字段使用函数分页查询优化-- 低效写法偏移量大时性能差 SELECT * FROM large_table LIMIT 1000000, 10; -- 高效写法使用索引列定位 SELECT * FROM large_table WHERE id 1000000 LIMIT 10;临时结果集处理对于复杂中间结果考虑使用临时表MySQL 8.0的CTE语法可提高可读性大数据集处理时可分阶段执行监控与调优定期检查慢查询日志使用Performance Schema监控查询性能对高频复杂查询考虑使用物化视图通过定时任务实现在最近的一个数据分析项目中通过重构一个包含5层嵌套的子查询为JOIN临时表的方式我们将查询时间从原来的23秒降低到了1.7秒。关键点在于识别出最内层的子查询实际上是对同一张表的重复扫描通过提取为临时表后只需扫描一次。