假设你要点外卖,数据库就是外卖小哥,执行计划就是他选择的路线:
SQL示例:
SELECT * FROM 外卖订单 WHERE 商家='奶茶店' AND 状态='已完成';
✅ 高效计划:用商家索引
快速定位奶茶店订单,再过滤状态
❌ 低效计划:扫描所有订单,一个个检查商家和状态(全表扫描)
外卖小哥要知道:
自动更新(推荐夜间自动进行):
-- Oracle自动任务
BEGIN
DBMS_STATS.GATHER_SCHEMA_STATS('外卖平台');
END;
手动更新(紧急修路):
-- 针对大表采样20%数据
EXEC DBMS_STATS.GATHER_TABLE_STATS('外卖平台', '订单表', estimate_percent=>20);
⚠️ 警告:别在午高峰更新!否则小哥会被卡在店里(锁表阻塞)
招式 | 适用场景 | 操作步骤(Oracle为例) |
---|---|---|
EXPLAIN | 纸上谈兵 | EXPLAIN PLAN FOR SELECT ... |
AUTOTRACE | 看执行报告 | SET AUTOTRACE TRACEONLY |
DBMS_XPLAN | 查历史SQL | SELECT * 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 |
字段 | 解读 | 危险信号 |
---|---|---|
Operation | 操作类型 | FULL SCAN 出现次数多 |
Starts | 执行次数 | 数值大≈绕远路 |
A-Rows/E-Rows | 实际/预估行数 | 差异大→统计信息过期 |
Cost | 优化器预估成本 | 数值越高越慢 |
“先右后左,先下后上”
示例计划:
NESTED LOOPS
INDEX SCAN 商家索引 -- 第1步:先执行右边
TABLE ACCESS 订单表 -- 第2步:再执行左边
就像外卖小哥先找奶茶店(索引),再取具体订单(表访问)
问题SQL:
SELECT * FROM 用户表 WHERE 年龄 BETWEEN 20 AND 30;
执行计划:
TABLE ACCESS FULL 用户表
诊断:
年龄索引
快速定位SELECT /*+ INDEX(用户表 年龄索引) */ ...
问题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;
题目:执行计划中出现SORT ORDER BY
且耗时高,应该怎么办?
A. 加内存 B. 删排序 C. 用索引
答案:C(创建排序字段的索引,避免物理排序)
题目:哪个现象说明统计信息不准?
A. E-Rows=100,A-Rows=105
B. E-Rows=100,A-Rows=10000
答案:B(实际行数远大于预估)
下期预告:《操控SQL优化技巧》
互动话题:你在学习SQL时遇到过哪些坑?欢迎评论区留言讨论!
️温馨提示:我是[随缘而动,随遇而安], 一个喜欢用生活案例讲技术的开发者。如果觉得有帮助,点赞关注不迷路