←

联合索引的列顺序,会被数据量改掉

这个接口统计近一个月的异常记录,再把结果推出去。响应接近 10 秒。链路追踪里,数据库大约占 65%,上游 HTTP 大约占 20%。

EXPLAIN 的 type 是 range,预估扫描大约 90 万行,而且有回表。时间列的取值更分散,所以第一版联合索引是 (operate_time, status)。它大约滤掉 80% 的行。上游同时从循环调用改成批量接口。接口降到大约 3 秒。

过了一段时间,同样的查询变成大约 16 秒。EXPLAIN 显示没有走这个索引,而是全表扫描。只按时间过滤,行数从大约 90 万涨到大约 600 万;再加上异常状态,只剩大约 3 万行。优化器认为先走时间不划算。

status 的取值很少,单看区分度很差。在这条查询里它反而有选择性,因为要的是那一小部分异常。索引改成 (status, operate_time):先把异常圈出来,再在这个范围里按时间查。响应降到大约 1.2 秒。

表还会继续变大。后续可以按月分区,或把不再访问的记录迁出这张表,避免优化器再做一次同样的选择。那一步当时没有做,索引调整本身已经上线。

列顺序不能按「哪一列更唯一」来排。要看这个查询实际留下多少行,而且这个比例会变。索引用当时的 EXPLAIN 验证过,数据量变了还要再验证一次。