theme: default themeName: "默认主题" title: "数据库查询慢到怀疑人生?这几个索引优化技巧让你的查询提速10倍"
数据库查询慢到怀疑人生?这几个索引优化技巧让你的查询提速10倍
上周接手一个老项目,首页加载要8秒。查了一圈,发现是数据库查询拖了后腿——一个看起来很简单的查询,执行了将近5秒。
DBA看了眼执行计划,淡淡地说了句:"索引没建好,重写SQL或者加索引吧。"
我不是DBA,但这些年踩过的坑够多了。今天就把几个实用的索引优化技巧分享出来,都是实战验证过的,不是教科书上的空话。
技巧一:最左前缀原则,别用错了
复合索引很多人会建,但用对的没几个。MySQL的复合索引遵循最左前缀原则,意思是:索引(a, b, c)只能用于a、ab、abc开头的查询条件。
我见过太多人这样写:
-- 索引是 (status, create_time)
SELECT * FROM orders WHERE create_time > '2024-01-01' AND status = 1;
看起来 status 和 create_time 都在条件里,但MySQL优化器可能会选择不使用索引,因为create_time跳过了最左列。
正确的写法是调整条件顺序,或者创建单独的索引。更好的做法是分析业务场景——如果按status筛选后再按时间排序是常见操作,就保留现有索引;如果经常要按create_time查,就建单独索引。
技巧二:别让函数毁了你的索引
这个坑我踩过无数次:
-- 假设create_time上有索引
SELECT * FROM orders WHERE DATE(create_time) = '2024-04-23';
explain一下,type是ALL,全表扫描。为什么?因为对列使用函数,MySQL就没法用索引了。
正确的姿势是这样写:
SELECT * FROM orders
WHERE create_time >= '2024-04-23 00:00:00' AND create_time < '2024-04-24 00:00:00';
同样的逻辑,但这次能走索引。范围查询比函数转换高效得多。
技巧三:覆盖索引,减少回表
什么是回表?简单说,普通索引存的是索引列的值和主键ID,查到索引记录后还要回主表去拿其他列的数据。这就是回表,多一次IO。
覆盖索引就是让查询需要的列都在索引里,不需要回表:
-- 索引 (user_id, status)
SELECT user_id, status FROM orders WHERE user_id = 10086;
这个查询只需要user_id和status,而索引里刚好有这两列,MySQL直接从索引拿数据,不用回表。性能提升非常明显,特别是高并发场景。
对于InnoDB,如果查询只需要主键,甚至不需要建额外索引,因为普通索引本身就包含了主键。
技巧四:索引不是越多越好
新手最爱犯的错误:给每个查询条件都建索引。结果INSERT、UPDATE变慢,磁盘空间浪费,优化器选择反而混乱。
我有条原则:单表索引数量不超过5个,除非有明确的业务需求。
怎么判断要不要建索引?我总结了个公式:
索引收益 = 查询频率 × 单次查询优化幅度 - 写入频率 × 索引维护成本如果一个字段每天都查,建索引能从5秒优化到0.5秒,那必须建。如果一个字段一年才查两次,建了索引反而拖慢日常写入,那就别建。
技巧五:定期分析索引使用情况
索引建多了,很多可能是浪费。MySQL提供了分析工具:
-- 查看索引使用统计(需要开启performance_schema)
SELECT OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, COUNT_READ, COUNT_FETCH FROM performance_schema.table_io_waits_summary_by_index_usage WHERE OBJECT_SCHEMA = 'your_database' ORDER BY COUNT_READ DESC;
如果发现某个索引 COUNT_READ 为 0 或很低,就要考虑是不是冗余索引。
另一个工具是`sys.schema_unused_indexes`视图,能直接列出未被使用的索引。定期清理这些僵尸索引,表会更轻盈。
实战案例:那个5秒查询怎么优化的
回到开头那个项目。原始查询长这样:
SELECT * FROM orders
WHERE user_id = 12345 AND status IN (1, 2, 3) ORDER BY create_time DESC LIMIT 20;
orders表有3000万条数据,user_id和status分别有索引,create_time也有索引。但MySQL只能选一个,结果选了个最差的,全表扫描。
优化方案:
1. 创建复合索引 `(user_id, status, create_time)` 2. 改写SQL,把IN改成OR或者用UNION ALL(视数据分布而定)
最终查询时间从5秒降到了0.3秒。首页加载时间从8秒变成3秒,用户满意度直接拉满。
最后说两句
索引优化不是玄学,是有迹可循的。核心就三点:
- 理解索引结构:B+树、最左前缀、覆盖索引,这些概念要吃透。
- 会用EXPLAIN:type、key、rows、Extra这几个字段,看一眼就知道查询有没有问题。
- 持续监控:索引不是建完就完事,数据分布会变,业务会变,索引也要跟着调整。
掌握这些,你的数据库就不会成为系统的瓶颈。有问题随时交流,实战出真知。
看完还有什么疑问吗?
如果文章没有覆盖到你的情况,欢迎联系我们咨询——免费解答,说清楚再决定要不要服务。
📞 服务热线:13708730161 💬 微信:eyc1689 📧 邮箱:service@eycit.com 🌐 https://www.eycit.com
易云城IT服务,您身边的IT专家。