线上数据库性能瓶颈,十有八九源于索引设计不当。慢查询不仅拖垮应用响应,还会引发连接池耗尽与级联雪崩。本文通过一个真实电商订单场景,拆解从 3 秒慢查询到 50 毫秒响应的完整优化链路。

慢查询案例引入

某电商订单服务暴露一条典型慢查询:

SELECT order_id, user_id, amount, status 
FROM orders 
WHERE user_id = 12345 AND created_at > '2024-01-01' 
ORDER BY created_at DESC 
LIMIT 20;

启用 EXPLAIN 分析后发现 type=ALL,全表扫描遍历 200 万行数据,耗时 3.2 秒。

覆盖索引:让查询「飞起来」

覆盖索引的核心思想是:索引本身包含查询所需的所有列,MySQL 无需回表。为上述查询设计复合索引:

CREATE INDEX idx_user_created_cover 
ON orders(user_id, created_at, order_id, amount, status);

再次 EXPLAIN 显示 type=rangeExtra=Using index,查询耗时骤降至 48 毫秒。

最左前缀原则

复合索引 (a, b, c) 必须按从左到右的顺序使用。以下查询能命中索引:

WHERE a = 1           -- OK
WHERE a = 1 AND b = 2 -- OK
WHERE a = 1 AND c = 3 -- a 命中,c 部分不命中

WHERE b = 2 单独使用时会导致索引失效,因为跳过了最左列 a

索引选择与成本模型

MySQL 8.0 的优化器基于成本模型选择索引。ANALYZE TABLE orders 可以更新统计信息,帮助优化器做出更精准的选择:

ANALYZE TABLE orders;
SHOW INDEX FROM orders;

常见误区

  1. 索引越多越好:过多索引会增加 INSERT/UPDATE 开销,每次写操作都要维护 B+ 树
  2. 对低选择性字段建索引:如 status='active' 过滤率低于 10%,索引收益有限
  3. IGNORE 强制使用索引USE INDEX(idx_name) 有时可以绕过优化器误判

索引优化不是玄学,而是基于执行计划的「精准外科手术」。每次上线前用 EXPLAIN 验证查询计划,是后端工程师的基本功。