当前位置:首页 > 问答 > 正文

SQL优化|查询流程 mysql执行顺序-mysqlsql执行顺序详解

🔍 MySQL查询执行顺序详解:原来SQL是这样跑起来的!

场景引入
小明写了个复杂的SQL查询,明明加了索引却还是慢如蜗牛🐌,同事瞥了一眼说:"你的WHEREHAVING顺序反了吧?" —— 这背后隐藏着MySQL的执行顺序玄机!今天我们就拆解这个"黑盒子"!


🚀 一、SQL语句的完整生命周期

当你在客户端敲下SELECT时,MySQL像流水线一样处理你的请求:

SELECT name, AVG(score) FROM students 
WHERE class_id = 3 
GROUP BY name 
HAVING AVG(score) > 80 
ORDER BY name 
LIMIT 10;

👉 实际执行顺序(重点!):
FROMWHEREGROUP BYHAVINGSELECTDISTINCTORDER BYLIMIT


🔧 二、分步拆解执行顺序

1️⃣ FROM & JOIN(确定数据源)

MySQL先定位要操作的表,如果是多表关联,此时执行JOIN操作:

FROM students 
LEFT JOIN classes ON students.class_id = classes.id

💡 优化点

  • 小表驱动大表(小表放JOIN左侧)
  • 避免SELECT *只取必要字段

2️⃣ WHERE(数据过滤)

在内存中逐行过滤,此时尚未分组

WHERE class_id = 3  -- 这里不能用聚合函数!

🚨 常见坑

  • WHERE中误用AVG()等聚合函数(应该放在HAVING
  • 对索引列使用或LIKE '%xx'导致索引失效

3️⃣ GROUP BY(数据分组)

按指定列合并数据,生成临时表:

GROUP BY name  -- 此时name相同的行会被合并

⚠️ 注意

SQL优化|查询流程 mysql执行顺序-mysqlsql执行顺序详解

  • GROUP BYSELECT只能出现分组字段或聚合函数
  • 大数据量分组可能产生临时表,引发性能问题

4️⃣ HAVING(分组后过滤)

分组结果进行筛选(类似WHERE但作用于组):

HAVING AVG(score) > 80  -- 这里才能用聚合函数!

🎯 对比WHERE

  • WHERE在分组前过滤单行
  • HAVING在分组后过滤组

5️⃣ SELECT(选择输出列)

此时才计算SELECT中的表达式:

SELECT name, AVG(score) as avg_score  -- 别名在此阶段生效

💥 易错点

  • 别名不能在WHERE中使用(执行时还不存在)
  • 计算密集型操作(如ROUND())影响性能

6️⃣ DISTINCT(去重)

如果有DISTINCT,此时会扫描并去重:

SELECT DISTINCT department  -- 去重消耗较大

🔧 优化建议

  • 优先用WHERE过滤减少数据量
  • 考虑用GROUP BY替代

7️⃣ ORDER BY(排序)

对结果集排序,可能用到临时文件:

SQL优化|查询流程 mysql执行顺序-mysqlsql执行顺序详解

ORDER BY avg_score DESC  -- 可用SELECT中的别名

💡 技巧

  • 对索引列排序更快
  • LIMITORDER BY配合可减少排序量

8️⃣ LIMIT(分页截取)

最后阶段才应用分页:

LIMIT 10  -- 前10条

⚠️ 大分页问题
LIMIT 10000,10会先读取10010行再丢弃,建议改用WHERE id > xxx


📊 三、执行顺序可视化

用EXPLAIN查看执行计划时,id列的顺序揭示了实际执行流:

EXPLAIN SELECT * FROM ... 

📌 关键观察点

  • id相同按从上到下执行
  • id不同,值越大越先执行

🛠️ 四、实战优化案例

问题SQL

SELECT class_name, COUNT(*) 
FROM students s
JOIN classes c ON s.class_id = c.id
WHERE s.score > 60
GROUP BY class_name
HAVING COUNT(*) > 5
ORDER BY COUNT(*) DESC
LIMIT 3;

优化思路

SQL优化|查询流程 mysql执行顺序-mysqlsql执行顺序详解

  1. 确保JOIN字段有索引
  2. HAVING COUNT(*) > 5提前到WHERE(如可能)
  3. EXPLAIN检查是否出现Using temporary(临时表)

🌟 总结精华

1️⃣ 顺序口诀
"饭(FROM)后(WHERE)果(GROUP)核(HAVING)
选(SELECT)独(DISTINCT)食(ORDER)粒(LIMIT)"

2️⃣ 性能关键

  • 尽量在WHERE阶段过滤掉最多数据
  • 避免中间结果集过大(尤其是分组和排序)

3️⃣ 终极工具
EXPLAIN + 慢查询日志是优化双剑合璧🗡️

下次写SQL时,想想MySQL是怎么"消化"你的语句的,对症下药才能事半功倍哦!✨

发表评论