Bootstrap

第十五篇 10分钟变身SQL优化大师 执行计划一看就懂

目录

    • 一、执行计划:SQL的导航仪
      • 1.1 导航仪是啥?点外卖秒懂!
    • 二、统计信息:路况实时更新
      • 2.1 为什么需要路况?
      • 2.2 如何更新路况?
    • 三、5招获取执行计划:小白必备
    • 四、3分钟破解执行计划密码
      • 4.1 关键字段速查表
      • 4.2 看执行顺序口诀
    • 五、实战:揪出SQL中的“堵车王”
      • 5.1 案例:索引失效的“鬼打墙”
      • 5.2 案例:连接顺序引发“大塞车”
    • 六、闯关挑战:测测你的优化段位
    • 七、新手村→王者进阶指南
      • 7.1 学习路线图

摘要:刚写好的SQL跑起来比蜗牛还慢?别删库跑路!本文将用点外卖、导航等生活例子,带你轻松看懂SQL执行计划,附赠【优化宝典】和互动习题,包教包会!


一、执行计划:SQL的导航仪

1.1 导航仪是啥?点外卖秒懂!

假设你要点外卖,数据库就是外卖小哥,执行计划就是他选择的路线:

  • 路线A:先取奶茶再拿炸鸡(顺序扫描)
  • 路线B:直接去综合商场一次拿齐(索引扫描)

SQL示例

SELECT * FROM 外卖订单 WHERE 商家='奶茶店' AND 状态='已完成';

高效计划:用商家索引快速定位奶茶店订单,再过滤状态
低效计划:扫描所有订单,一个个检查商家和状态(全表扫描)


二、统计信息:路况实时更新

2.1 为什么需要路况?

外卖小哥要知道:

  • 奶茶店今天订单量(表行数)
  • 不同商家的分布区域(数据分布)

2.2 如何更新路况?

自动更新(推荐夜间自动进行):

-- Oracle自动任务
BEGIN
  DBMS_STATS.GATHER_SCHEMA_STATS('外卖平台');
END;

手动更新(紧急修路):

-- 针对大表采样20%数据
EXEC DBMS_STATS.GATHER_TABLE_STATS('外卖平台', '订单表', estimate_percent=>20);

⚠️ 警告:别在午高峰更新!否则小哥会被卡在店里(锁表阻塞)


三、5招获取执行计划:小白必备

招式适用场景操作步骤(Oracle为例)
EXPLAIN纸上谈兵EXPLAIN PLAN FOR SELECT ...
AUTOTRACE看执行报告SET AUTOTRACE TRACEONLY
DBMS_XPLAN查历史SQLSELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('sql_id'))
10046 Trace侦探模式ALTER SESSION SET EVENTS '10046 trace name context forever, level 12';
AWR报告对比历史堵车记录运行@?/rdbms/admin/awrsqrpt.sql

四、3分钟破解执行计划密码

4.1 关键字段速查表

字段解读危险信号
Operation操作类型FULL SCAN出现次数多
Starts执行次数数值大≈绕远路
A-Rows/E-Rows实际/预估行数差异大→统计信息过期
Cost优化器预估成本数值越高越慢

4.2 看执行顺序口诀

“先右后左,先下后上”
示例计划:

NESTED LOOPS
  INDEX SCAN 商家索引  -- 第1步:先执行右边
  TABLE ACCESS 订单表  -- 第2步:再执行左边

💡 就像外卖小哥先找奶茶店(索引),再取具体订单(表访问)


五、实战:揪出SQL中的“堵车王”

5.1 案例:索引失效的“鬼打墙”

问题SQL

SELECT * FROM 用户表 WHERE 年龄 BETWEEN 20 AND 30;

执行计划

TABLE ACCESS FULL 用户表

🔍 诊断

  • 预期:走年龄索引快速定位
  • 实际:全表扫描10万行!
    病因:年龄在20-30的用户占了40%,优化器觉得全表更快!
    💊 药方:强制使用索引(慎用!):
SELECT /*+ INDEX(用户表 年龄索引) */ ...

5.2 案例:连接顺序引发“大塞车”

问题SQL

SELECT * FROM 订单表 o JOIN 用户表 u ON o.user_id = u.id;

执行计划

HASH JOIN
  TABLE ACCESS FULL 用户表  -- 先扫描100万用户
  TABLE ACCESS FULL 订单表  -- 再扫描500万订单

🚦 堵点:两个大表全扫描,内存撑爆!
🚀 优化:先过滤再关联:

SELECT * 
FROM (SELECT * FROM 订单表 WHERE 状态='已完成') o 
JOIN 用户表 u ON o.user_id = u.id;

六、闯关挑战:测测你的优化段位

  1. 题目:执行计划中出现SORT ORDER BY且耗时高,应该怎么办?
    A. 加内存 B. 删排序 C. 用索引
    答案:C(创建排序字段的索引,避免物理排序)

  2. 题目:哪个现象说明统计信息不准?
    A. E-Rows=100,A-Rows=105
    B. E-Rows=100,A-Rows=10000
    答案:B(实际行数远大于预估)


七、新手村→王者进阶指南

7.1 学习路线图

  1. 青铜:《SQL必知必会》、LeetCode简单题
  2. 白银:《高性能MySQL》、AWR报告分析
  3. 王者:执行计划绑定、SQL重写规则

🎯下期预告:《操控SQL优化技巧》
💬互动话题:你在学习SQL时遇到过哪些坑?欢迎评论区留言讨论!
🏷️温馨提示:我是[随缘而动,随遇而安], 一个喜欢用生活案例讲技术的开发者。如果觉得有帮助,点赞关注不迷路🌟

;