场景引入:
小明写了个复杂的SQL查询,明明加了索引却还是慢如蜗牛🐌,同事瞥了一眼说:"你的WHERE
和HAVING
顺序反了吧?" —— 这背后隐藏着MySQL的执行顺序玄机!今天我们就拆解这个"黑盒子"!
当你在客户端敲下SELECT
时,MySQL像流水线一样处理你的请求:
SELECT name, AVG(score) FROM students WHERE class_id = 3 GROUP BY name HAVING AVG(score) > 80 ORDER BY name LIMIT 10;
👉 实际执行顺序(重点!):
FROM
→ WHERE
→ GROUP BY
→ HAVING
→ SELECT
→ DISTINCT
→ ORDER BY
→ LIMIT
MySQL先定位要操作的表,如果是多表关联,此时执行JOIN
操作:
FROM students LEFT JOIN classes ON students.class_id = classes.id
💡 优化点:
JOIN
左侧) SELECT *
只取必要字段 在内存中逐行过滤,此时尚未分组:
WHERE class_id = 3 -- 这里不能用聚合函数!
🚨 常见坑:
WHERE
中误用AVG()
等聚合函数(应该放在HAVING
) LIKE '%xx'
导致索引失效 按指定列合并数据,生成临时表:
GROUP BY name -- 此时name相同的行会被合并
⚠️ 注意:
GROUP BY
后SELECT
只能出现分组字段或聚合函数 对分组结果进行筛选(类似WHERE
但作用于组):
HAVING AVG(score) > 80 -- 这里才能用聚合函数!
🎯 对比WHERE:
WHERE
在分组前过滤单行 HAVING
在分组后过滤组 此时才计算SELECT
中的表达式:
SELECT name, AVG(score) as avg_score -- 别名在此阶段生效
💥 易错点:
WHERE
中使用(执行时还不存在) ROUND()
)影响性能 如果有DISTINCT
,此时会扫描并去重:
SELECT DISTINCT department -- 去重消耗较大
🔧 优化建议:
WHERE
过滤减少数据量 GROUP BY
替代 对结果集排序,可能用到临时文件:
ORDER BY avg_score DESC -- 可用SELECT中的别名
💡 技巧:
LIMIT
和ORDER BY
配合可减少排序量 最后阶段才应用分页:
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;
优化思路:
JOIN
字段有索引 HAVING COUNT(*) > 5
提前到WHERE
(如可能) EXPLAIN
检查是否出现Using temporary
(临时表) 1️⃣ 顺序口诀:
"饭(FROM)后(WHERE)果(GROUP)核(HAVING)
选(SELECT)独(DISTINCT)食(ORDER)粒(LIMIT)"
2️⃣ 性能关键:
WHERE
阶段过滤掉最多数据 3️⃣ 终极工具:
EXPLAIN + 慢查询日志
是优化双剑合璧🗡️
下次写SQL时,想想MySQL是怎么"消化"你的语句的,对症下药才能事半功倍哦!✨
本文由 喻芳懿 于2025-07-30发表在【云服务器提供商】,文中图片由(喻芳懿)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/488849.html
发表评论