智用指南
霓虹主题四 · 更硬核的阅读氛围

索引优化器性能调优:让数据库跑得更快的实战技巧

发布时间:2025-12-14 03:00:28 阅读:345 次

索引不是越多越好

很多人一看到查询慢,第一反应就是加索引。可实际情况是,表上索引太多,反而拖慢写入速度。每次INSERT、UPDATE、DELETE操作,数据都得同步维护所有相关索引,就像你搬家时每多带一个箱子,路上就得多花一分力气。

比如某电商后台订单表,原本只有主键和用户ID索引,后来陆续加上了订单状态、创建时间、支付方式等五个索引。结果新增订单的响应时间从80ms涨到了220ms。删掉三个低频查询用的冗余索引后,写入性能立刻回升。

识别无效索引有妙招

MySQL可以通过information_schema.statistics查看索引使用情况,配合performance_schema.table_io_waits_summary_by_index_usage找出长期未被使用的索引。

SELECT object_schema, object_name, index_name
  FROM performance_schema.table_io_waits_summary_by_index_usage
  WHERE index_name IS NOT NULL
    AND count_read = 0
    AND object_schema NOT IN ('mysql', 'information_schema')
  ORDER BY object_schema, object_name;

这条语句能列出从未被读取过的索引,基本可以判定为“僵尸索引”,清理它们不会影响业务,还能释放存储空间。

组合索引的顺序很关键

有个常见误区:把WHERE条件里出现的字段全塞进索引就行。其实顺序决定成败。假设经常按“城市 + 年龄 + 注册时间”筛选用户,那么INDEX(city, age, created_at)是合理选择。

B+树索引的结构决定了它遵循最左匹配原则。如果你的查询只用了age和created_at,这个索引就用不上。但若查询包含city和age,哪怕没有created_at,也能走索引前缀。

就像坐地铁,必须按站顺序经过,不能跳过前几站直接到后面去。

覆盖索引减少回表代价

有时候你会发现某个查询明明走了索引,却还是慢。问题可能出在“回表”上。普通二级索引查到主键后,还得再拿主键去聚簇索引捞数据,这一来一回耗资源。

如果索引本身就包含了查询所需的所有字段,就不需要回表了。比如用户列表页只需要显示昵称和注册时间,可以把这两个字段都放进索引:

ALTER TABLE users ADD INDEX idx_status_nickname_time
 (status, nickname, created_at);

这样SELECT nickname, created_at FROM users WHERE status = 1就能直接从索引中拿到结果,效率提升明显。

执行计划要看懂

EXPLAIN是调优的必备工具。type显示ALL?那是全表扫描,得想办法改成range或ref。Extra里出现Using filesort或Using temporary也不妙,意味着排序或分组用了临时表。

举个例子,有条SQL查某天的订单总金额:

SELECT SUM(amount) FROM orders
WHERE DATE(created_at) = '2024-03-15';

即便created_at有索引,DATE()函数也会让它失效。改成区间查询就能命中索引:

SELECT SUM(amount) FROM orders
WHERE created_at >= '2024-03-15 00:00:00'
  AND created_at < '2024-03-16 00:00:00';

这样一改,rows从十几万降到几百,执行时间从3秒变成0.05秒。

别忽视统计信息更新

器依赖表的统计信息来做决策。如果长时间没分析表,它可能会误判数据分布,选错索引。特别是大表做批量导入后,记得运行ANALYZE TABLE。

ANALYZE TABLE orders;

这会让优化器重新估算索引基数,从而做出更合理的执行计划选择。