压测库 800 万行订单,tenant_id 只有一个值,status 分布 99% 是 1。压测 SQL 走索引只要 3 毫秒,线上同样的查询 120 毫秒,explain 的 rows 差 40 倍。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,数据全落在同一租户,联合索引第一列等于常量,优化器把它当免费过滤条件。线上租户有 2000 多个,同一个查询要扫的分区多得多。状态分布也失真,回表行数完全不是一个量级。
「压测数据分布」这类改动最怕改一半,回滚脚本先准备好,再动生产。别只看报错的最后一行,往上看几行,真正的起因通常在上面。
INSERT INTO orders (tenant_id, status, create_time) SELECT (random()*500)::int, (random()*5)::int, now() - (random()*365 || ' days')::interval FROM generate_series(1, 8000000);
同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。
具体做法是,按线上租户数量和订单比例造数据 至少 500 个租户;status 按真实占比分布 别全填 1;时间字段铺满 12 个月 保证范围查询有区分度;造完跑一遍 explain 对比 rows 和线上是否接近。
最后用这个标准收尾,压测库和线上同一条 SQL 的 explain rows 相差在 2 倍以内。
