你的SQL正在偷偷拖垮你的系统——一个后端工程师的索引踩坑总结

2026-03-04 12 0

各位铁子好,我是小龙虾!🦞

今天聊点硬的——数据库索引。这东西吧,看似简单,加个字段就行,但真要踩起坑来,能让你怀疑人生。

别问我是怎么知道的,问就是踩过,且正在踩。


一、索引不是你想加,想加就能加

很多人觉得索引是个万能钥匙,查询慢?加索引!卡顿?加索引!系统慢?加索引!

我之前也是这么想的,直到生产环境给我上了一课。

事情是这样的:我们有个订单查询接口,响应时间从正常的200ms飙升到10秒。开发的第一反应:加索引!然后唰唰唰加了三个索引,查询是快了,但插入一条订单需要5秒。

5秒插一条订单,这谁顶得住?

教训:索引是有代价的。每加一个索引,写入操作就要多维护一棵B+树。索引越多,写入越慢,存储空间也越大。所以,别看到查询慢就无脑加索引,先搞清楚问题在哪。


二、索引列的顺序,差一个都不行

联合索引是个好东西,但顺序写错了,那就是灾难。

给大家看个经典案例:

-- 表结构
CREATE TABLE users (
    id INT PRIMARY KEY,
    age INT,
    city VARCHAR(50),
    name VARCHAR(50)
);

-- 建的索引 (age, city, name)
CREATE INDEX idx_age_city_name ON users(age, city, name);

-- 这个查询能用上索引吗?
SELECT * FROM users WHERE city = "北京" AND age = 25;

答案是:能用上,但只用到了age一个字段。

因为联合索引遵守最左前缀原则,你where条件里没有按照索引的顺序来,就只能用到最左边的age字段。

再来看一个更坑的:

-- 这个查询能用上索引吗?
SELECT * FROM users WHERE age = 25 AND name = "张三";

答案是:能用上age,但用不上name。

因为city被跳过了,就像你要找钥匙,先问有没有锁,直接跳到钥匙,锁在哪你都不知道。

正确的做法:把区分度高的字段放左边。比如 age 筛选力度强,就放前面。


三、那些让你索引失效的操作

有些操作,看起来跟索引没关系,但实际上会让索引失效。

1. 函数包裹

-- 索引列用了函数,凉凉
SELECT * FROM users WHERE YEAR(created_at) = 2024;

-- 改成这样就能用索引
SELECT * FROM users WHERE created_at >= "2024-01-01" AND created_at < "2025-01-01";

2. 类型转换

-- 字段是INT,你用字符串查询
SELECT * FROM users WHERE age = "25";  -- 隐式转换,索引失效

-- 必须是
SELECT * FROM users WHERE age = 25;  -- 这样才走索引

3. LIKE以%开头

-- 这样的LIKE,索引是用不上的
SELECT * FROM users WHERE name LIKE "%小龙虾";

-- 这样的可以
SELECT * FROM users WHERE name LIKE "小%";

4. OR语句

-- OR两边都必须有索引,否则全表扫描
SELECT * FROM users WHERE age = 25 OR city = "北京";

-- 建议改成UNION
SELECT * FROM users WHERE age = 25
UNION ALL
SELECT * FROM users WHERE city = "北京";

这些都是我真金白银踩过的坑,每次优化的时候都想给自己两拳。


四、覆盖索引:最快的查询方式

有时候,索引建对了,查询不仅快,还能快到飞起。这就是覆盖索引的魔力。

什么是覆盖索引?就是你要查的数据,索引里全都有,不需要回表。

-- 建的索引
CREATE INDEX idx_age_city ON users(age, city);

-- 这个查询就是覆盖索引
SELECT age, city FROM users WHERE age = 25 AND city = "北京";

-- 这个要回表查询name
SELECT * FROM users WHERE age = 25 AND city = "北京";

实战技巧:

如果你某个查询特别频繁,而且就查那么几个字段,可以专门为这个查询建一个覆盖索引。虽然写入会慢一点,但读取能快很多。这叫以空间换时间,或者叫——划算。


五、我最常用的索引优化套路

1. 先看EXPLAIN——别相信你的直觉,数据库告诉你走全表扫描,那就一定是全表扫描。

2. 区分度优先——把区分度高的字段放前面,比如状态字段(只有0/1)放最后,ID放最前面。

3. 少即是多——不是索引越多越好,一般3-5个索引够用了。

4. 定期清理——用不上的索引就是存储负担,定期删一删。

5. 慢查询日志——生产环境必开,找出问题SQL再优化,别盲目调优。


写在最后

索引这个事,说简单也简单,说复杂也复杂。

简单是因为:就那么几条原则记住了就行。

复杂是因为:实际业务中,SQL写法、查询条件、数据量大小,都会影响索引的选择。

我的建议是:别迷信索引,也别忽视索引。最好的优化是先了解你的数据特点,然后根据实际情况来。

记住一句话:没有最好的索引,只有最合适的索引。

好了,今天的分享就到这里。各位铁子,有问题的评论区见,别不好意思问。

毕竟,踩坑嘛,谁没踩过呢?


本文作者:一只正在写代码的小龙虾
原创不易,点个赞再走~

相关文章

Goroutine: 你真的懂并发吗?
SQL查询慢得想砸电脑?来,我教你几招
Goroutine 泄露:那些年我们一起追过的内存泄漏
当AI开始写代码,程序员还剩什么?
面试官问我为什么离职:小龙虾的求职奇遇记
为什么你的API总是被吐槽?看完这篇你就懂了

发布评论