📊 SQL 入门 Day 25:查询优化实战 —— 从 EXPLAIN 到索引的完整排查流

这是 SQL 学习路线的收官篇。前面学了索引、事务、锁、存储过程,今天把它们串起来:一条慢 SQL 到手,如何系统地定位、分析、优化?掌握这套方法论,你就能从「会写 SQL」进阶到「能救慢查询」。

场景引入

线上告警:orders 表 500 万行,下面这条查询跑了 12 秒:

sql 复制代码
SELECT o.id, o.order_no, u.name
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE o.status = 'PAID'
  AND o.created_at > '2026-06-01'
ORDER BY o.created_at DESC
LIMIT 20;

优化四步法

第 1 步:EXPLAIN 看执行计划

sql 复制代码
EXPLAIN SELECT ...;  -- 同上 SQL

-- 关键输出
-- type: ALL          ← 全表扫描,最差
-- key: NULL          ← 没走任何索引
-- rows: 5000000      ← 扫了 500 万行
-- Extra: Using filesort  ← 排序没走索引,额外文件排序

看懂 type 优先级 (好→坏): system > const > eq_ref > ref > range > index > ALL 看到 ALL 或 index 且 rows 巨大,就是优化信号。

第 2 步:补索引,消除全表扫描

sql 复制代码
-- status + created_at 复合索引:WHERE 过滤 + ORDER BY 排序一次搞定
ALTER TABLE orders ADD INDEX idx_status_created (status, created_at);

-- 再次 EXPLAIN:
-- type: ref  |  key: idx_status_created  |  rows: 12000
-- Extra: 不再有 Using filesort ✅(排序已走索引)

索引设计要点:

  • 等值条件放前面(status),范围条件放后面(created_at)------最左前缀原则
  • 让 ORDER BY 直接吃索引,消灭 filesort
  • 区分度高的列优先(status 只有几个值,单独建索引意义不大,必须和其他列组合)

第 3 步:改写 SQL,减少无效开销

sql 复制代码
-- ❌ 原写法的问题:
-- 1. SELECT 不需要的列(o.* 会拖累回表)
-- 2. LIMIT 20 但排序要排完所有匹配行

-- ✅ 优化后:
SELECT o.id, o.order_no, u.name
FROM orders o
INNER JOIN users u ON o.user_id = u.id   -- 业务上 LEFT JOIN 可改 INNER
WHERE o.status = 'PAID'
  AND o.created_at > '2026-06-01'
ORDER BY o.created_at DESC
LIMIT 20;

其他高频改写:

  • 避免 SELECT *:只取需要的列,减少回表和网络传输

  • 深分页优化 :LIMIT 100000, 20 改成子查询定位游标

    sql 复制代码
    SELECT ... FROM orders
    WHERE id > (SELECT id FROM orders ORDER BY id LIMIT 100000, 1)
    ORDER BY id LIMIT 20;
  • 函数包裹列会废索引 :WHERE YEAR(created_at) = 2026 → 改成范围条件 created_at >= '2026-01-01' AND created_at < '2027-01-01'

第 4 步:用慢查询日志验证

sql 复制代码
-- 开启慢查询日志(MySQL)
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;  -- 超过 1 秒的记录

-- 优化后实测:12s → 80ms,rows 从 500 万降到 1.2 万

注意事项

  • ⚠️ 索引不是越多越好 :每个索引都拖慢写入,冗余索引((a,b) 与 (a))要定期清理
  • ⚠️ LIKE '%xxx' 前置通配符不走索引 ;OR 连接的条件可能放弃索引,可用 UNION ALL 拆分
  • ⚠️ 数据量小时(万级以内)全表扫描可能比走索引更快,先 EXPLAIN 再动手,别盲目加索引
  • 💡 EXPLAIN ANALYZE(MySQL 8.0+)能给出实际执行时间和行数,比单纯 EXPLAIN 更接近真相
  • 💡 线上优化套路:慢查询日志 → 找 Top N 慢 SQL → EXPLAIN → 补索引/改写 → 回归验证,形成闭环

总结

25 天路线收官:从 SELECT 语法到索引原理,从事务隔离到锁机制,最后落到查询优化实战------SQL 的核心不是「会写」,而是「写得快、写得稳」。这套 EXPLAIN 排查流,就是你在生产环境最常用的看家本领。🎉

相关推荐
明月_清风12 小时前
Muse 登顶 App Store 第一,SDK 直接开源:AI Agent 开始进入下一个阶段
人工智能·后端
Seraphina3614 小时前
SQLI-labs(一)黑盒全流程
sql·安全·web安全
hsfxuebao14 小时前
Loop Engineering 保姆级教程 + 项目实战
人工智能·后端
打工仔折腾 AI15 小时前
从 Demo 到生产级 Agent:8 个关键设计机制与 Python 实现拆解
java·jvm·人工智能·后端·python·langchain·ai agent 实战
架构技术专栏15 小时前
交叉熵:AI 怎样给概率预测打分
后端
IT_陈寒17 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
要努力啊46917 小时前
用 Codex 加速 Java 开发:从代码生成到测试覆盖的完整实战
后端
dora17 小时前
LangChain4j 新手入门实战教程(Java版)
后端·langchain·agent
蜗牛互联网17 小时前
MongoDB Atlas Agent Engine之后,如何用版本门禁防止陈旧写入
java·数据库·人工智能·后端·mongodb
付威202317 小时前
Rust 生命周期:为什么要有它,实际代码里到底怎么用?
后端