八股 ①:索引与执行计划 20 问

第一步:把这八周踩过的性能知识点,变成能脱口而出的 60–90 秒口述。

学 20 min
练 60 min
盘 40 min
共 120 分钟

学 · 20 min

  1. 01口述答案的结构:结论先行 -> 原因 -> 举例 -> 边界

  2. 02每题控制在 60–90 秒

练 · 100 min

  1. 把页面底部「性能与索引」8 问 + 自己补 12 问,写成 20 题
    参考答案

    页面 8 问之外,自补 12 问按三类分:① 原理(B-tree 为什么快、PG 的索引与堆是什么关系);② 失效场景(列上套函数、前导 % 模糊、<>、类型不匹配);③ 实战(EXPLAIN 怎么读、cost 估算和 actual 偏差说明统计信息过期、三种 join 算法的选择依据、索引的写放大代价)。每题先写一句话答案钉住结论,口述稿再扩。

  2. 每题写一份 60–90 秒的口述稿
    参考答案

    60–90 秒 ≈ 200–280 字,四段结构:结论先行(一句话)→ 原因(为什么成立)→ 例子(必须用自己在 100 万行 orders 上跑出的真实数字)→ 边界(什么时候不成立)。「大概几秒」这种模糊话一追问就穿帮。

  3. 录音,回放,标出讲得别扭的地方(那就是没想清楚的地方)
    参考答案

    回放三查:① 嗯啊超过 3 秒的卡壳处 = 那里没想清楚,标时间戳;② 口头禅(「然后」「就是说」)出现的频次;③ 超过 90 秒的题 = 该砍例子了。

  4. 重讲一遍被标记的题
    参考答案

    只重讲被标记的题:脱稿、计时、一次讲到位。隔天再抽查一遍讲过的题——隔天还能流畅讲出来,才算真的会了。

  5. 挑 3 题预设追问(「那如果数据量再大 10 倍呢?」)并准备答案
    参考答案

    追问答题模板:先说「结论会不会变」,再说「哪个假设失效了」,最后给替代方案。三个固定方向:数据量大 10 倍、写多读少还建吗、为什么不用别的方案。挑的 3 题选自己最没底的,别挑最顺的。

过关标准 20 题都能脱稿讲完,其中 5 题能应对一轮追问。

今日复盘

  1. 把 D42 的三条优化整理成一份完整案例文档
    参考答案

    七段结构:背景(库的量级、业务场景,两三句)-> 现象(谁报的、什么症状,量化成超时/耗时数字)-> 定位过程(用了什么工具拿到哪条 SQL,贴 pg_stat_statements 或慢日志的证据)-> 计划对比(优化前后 explain analyze 并排,标出最贵节点怎么消失的)-> 方案(改了什么、为什么)-> 结果数据(前后耗时对比表)-> 反思(重来会怎么做、监控能不能更早发现)。每一段都要有数字,没有数字的段落删掉重写。

  2. 写出 N+1 的具体现象,并给出 JOIN 或批量查询的改法
    参考答案

    识别特征比改法更重要:应用日志里同一模板的语句海量出现,基本就是 N+1。ORM 懒加载是重灾区,列表场景必须显式预取。

    -- 现象:后端先取 100 个订单,再循环逐个查用户 = 101 次往返
    -- 日志特征:同一语句模板几毫秒内刷屏 100 次
    
    -- 改法一:join 一次取回
    select o.id, o.total_amount, u.name as 用户名
    from orders o
    join users u on u.id = o.user_id
    where o.status = 2
    order by o.created_at desc
    limit 100;
    
    -- 改法二:数组参数批量取(ORM 里就是预取)
    select id, name from users
    where id = any((select array_agg(user_id)
                    from (select user_id from orders
                          where status = 2
                          order by created_at desc limit 100) t));
  3. 五步法:定位 -> 分析 -> 假设 -> 验证 -> 回归
    易错点

    跳过「分析」直接加索引是玄学优化:碰巧好了也不知道为什么,下次照样抓瞎。