WEEK 06

两年之后:索引与执行计划

时间快进:公司跑了一年多,订单冲到一百万,日报从一开始的秒出变成一分多钟。老板的原话:「它是不是坏了?」你的任务:让它快回去。
目标:看得懂 EXPLAIN ANALYZE,能说清一条查询为什么慢、加什么索引能救。
0 / 7 天
剧情 「时间快进」日:把库冲到 100 万订单 / 250 万明细 / 80 万支付 / 50 万登录。灌完你会发现,上周还秒出的查询现在慢得离谱--先建第一个索引救急,顺便搞懂它为什么快。
练 · 55 min
  1. 跑 seed.sql「W6」段大灌数,各表 count(*) 核对行数
  2. 记录 3 条常用查询的基线耗时(\timing,比如按用户查订单)
  3. 对 orders.user_id 无索引查询计时,建索引后再计时,记录倍数
  4. 用 pg_relation_size 对比表和索引各自占多大
  5. 在有索引和无索引的表上各批量插 10 万行,对比写入耗时
过关说出加索引前后的倍数;能主动讲出 PG 与 MySQL 在表组织方式上的差异--这是很好的加分点。
专注视图 ->
剧情 不同的慢法用不同的索引:状态列只有几个值、搜索要忽略大小写、商品名要做全文搜。一个 B-tree 打不了天下。
练 · 60 min
  1. 给 status = 'pending' 建部分索引,对比它和全量索引的大小
  2. 建 lower(email) 表达式索引,验证 where lower(email)=... 能命中
  3. 加一个 jsonb 列,建 GIN 索引并做包含查询
  4. 在时间列上分别建 B-tree 和 BRIN,对比索引大小
  5. 用 tsvector + GIN 做一次商品名全文检索
过关能各举一个部分索引和表达式索引的真实用途。
专注视图 ->
剧情 报表查询都带着「某用户的某时间段」--单个索引救不了组合条件。
练 · 60 min
  1. 建 (user_id, created_at) 复合索引,测三种查询(只用 user_id / 只用 created_at / 两者都用)是否命中
  2. 把列顺序反过来再建一次,重测上面三种查询
  3. 只 SELECT 索引里的列,观察计划里出现 Index Only Scan
  4. 用 INCLUDE 把 total_amount 加进索引,验证仍是 Index Only Scan
  5. 查 pg_stats 看几个列的 n_distinct,判断选择性高低
过关给定三条查询,能设计出「最少数量」的索引集合并说明理由。
专注视图 ->
剧情 老板问「到底慢在哪」。你不能再说「感觉是索引问题」--要拿执行计划说话。
练 · 55 min
  1. 挑 5 条查询做 EXPLAIN (ANALYZE, BUFFERS),逐行写注释
  2. 找出一条估算 rows 与实际相差 10 倍以上的查询,分析原因
  3. 找一个 Nested Loop 节点,用 loops 算出它的真实总耗时
  4. 对同一条 SQL 跑 EXPLAIN 和 EXPLAIN ANALYZE,说出区别
  5. 用 FORMAT JSON 输出一次,观察结构
过关拿到一份陌生执行计划,能在 2 分钟内指出瓶颈在哪个节点、依据是什么。
专注视图 ->
剧情 同一条查询,优化器有时走索引有时全表扫,有时 Hash Join 有时 Nested Loop。你要能看懂它的选择逻辑。
练 · 60 min
  1. 逐步放宽 WHERE 的选择率,观察计划从 Index Scan -> Bitmap -> Seq Scan 的切换点
  2. 用 SET enable_hashjoin = off 强制换算法,对比耗时
  3. 小表连大表,观察优化器选谁做驱动表(hash 表建在哪边)
  4. 把 work_mem 调到 64kB,观察 Hash Join 落盘(计划里出现 Batches > 1)
  5. 整理一张「三种 join 算法 × 适用条件 × 复杂度」对比表
过关能说出三种 join 算法各自的复杂度和前提条件(如 Merge Join 需要有序输入)。
专注视图 ->
剧情 索引建了,查询还是慢?你逐个复现六种「索引装死」的写法,还发现统计信息过期会让优化器选错路。
练 · 65 min
  1. 逐个复现 6 种失效场景,每种都保存失效前后的执行计划
  2. 把 date(created_at) = '2026-01-01' 改写成范围查询,验证索引恢复命中
  3. 用 varchar 列与整数比较,观察隐式转换导致的全表扫
  4. 大批量更新后先查计划,再手动 ANALYZE,对比计划变化
  5. 装 pg_stat_statements,找出耗时 TOP10 的语句
过关产出一张「失效写法 -> 正确写法」对照表,至少 6 行,每行附执行计划证据。
专注视图 ->
剧情 交付日:从 pg_stat_statements 里挑出最慢的三条,把它们救活,写成可以进简历的案例。
练 · 85 min
  1. 从 pg_stat_statements 挑出 3 条秒级查询作为目标
  2. 逐条记录优化前的 EXPLAIN ANALYZE 和耗时
  3. 提出假设 -> 加索引或改写 SQL -> 验证
  4. 记录优化后的计划与耗时,算出提升倍数
  5. 整理成对比表格:查询 | 优化前 | 优化后 | 手段 | 提升倍数
过关三条查询都有明确提升倍数,且能解释每一条为什么快了。这是简历上可以直接写的东西。
专注视图 ->