一个慢查询足以拖垮整个系统。在我们经手的项目中,约 60% 的性能问题最终追溯到数据库层面——索引缺失、SQL 写法不佳、连接池配置不当是三大元凶。
索引不是越多越好
很多开发者的第一反应是"加个索引"。但索引并非免费午餐——每个索引都会增加写入成本(INSERT/UPDATE/DELETE 都需维护索引),并占用额外磁盘空间。一个被过度索引的表,写入性能可能下降 50% 以上。
正确的索引策略:基于慢查询日志分析实际高频查询 → EXPLAIN 分析执行计划 → 针对性地建立联合索引。记住"最左前缀"原则:(a, b, c) 联合索引可覆盖 WHERE a=1 和 WHERE a=1 AND b=2,但无法覆盖 WHERE b=2。对于排序和分组操作,索引列顺序应与 ORDER BY / GROUP BY 顺序一致。
🔍 EXPLAIN 解读关键字段:type 列应避免 ALL(全表扫描)和 index(全索引扫描),目标是 ref/eq_ref/range;rows 列表示预估扫描行数,数字越小越好;Extra 列出现 Using filesort 或 Using temporary 说明需要优化 ORDER BY 或 GROUP BY。
一个真实的优化案例
某订单列表查询耗时 5.8 秒。EXPLAIN 分析发现:type=ALL(全表扫描 200 万行)+ Using filesort(文件排序)+ Using temporary(临时表)。优化三步走:
- 建立 (user_id, created_at DESC) 联合索引 → type 变为 range,rows 降至 500
- 添加 LIMIT 20 分页 → 避免一次加载所有数据
- 使用覆盖索引(SELECT user_id, amount, created_at)→ Extra 变为 Using index,消除回表查询
优化后耗时:5.8s → 80ms(↓98.6%)。
📋 数据库优化自检清单
- □ 慢查询日志是否开启?(slow_query_log = ON,long_query_time = 1s)
- □ 高频查询是否用 EXPLAIN 验证过执行计划?type 列是否有 ALL?
- □ 分页查询是否有深度分页问题?(OFFSET 过大改用游标分页)
- □ 连接池大小是否合理?(公式:核心数 × 2 + 有效磁盘数)
- □ 是否有未命中索引的排序/分组操作?
- □ 大表是否考虑过分区或归档策略?