做后端开发这些年,我见过最多的迷惑行为就是:数据库一慢,加索引。查询卡了,加索引。老板问为什么这么慢,加索引。
兄弟,你加的是索引,不是魔法杖啊。
今天我要说一个大多数教程都不会告诉你的真相:你的索引,可能从一开始就没生效过。
一个真实的血案
之前有个项目,用户反应用户列表加载巨慢,页面转圈转好几秒。我一看,慢查询日志里躺着一条这样的SQL:
SELECT * FROM users WHERE status = 1 AND age > 18 AND city = "北京";
表结构是这样的:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
status TINYINT,
age INT,
city VARCHAR(50),
INDEX idx_status_age_city (status, age, city)
);
三列联合索引,完美!按理说应该很快吧?EXPLAIN走起。
结果返回的是ALL——全表扫描。
我当时的表情:
问号脸.jpg
索引明明就在那里,为什么不用?
问题出在哪里?
答案是索引列参与运算。
看这条SQL:
WHERE age > 18
表面上很正常。但如果你稍微改一下:
WHERE age + 1 > 19
数据库拿到这个条件,第一反应是:我怎么知道age+1之后对应的是哪一列?索引排好序的是age的值,不是age+1的值。
所以——索引列做任何运算,索引必失效。
但是!重点来了。
你可能会说,我没对age做运算啊,就一个 > 18,凭什么失效?
因为类型隐式转换。
真正的凶手:类型转换
我建议你现在就打开你的数据库,执行这个实验:
EXPLAIN SELECT * FROM users WHERE phone = 13800138000;
如果你用的是MySQL,你会看到这条SQL走了全表扫描。
为什么?
因为phone是VARCHAR类型,但你传的是一个数字。MySQL会把字符串转换成数字,相当于:
CAST(phone AS DOUBLE) = 13800138000
索引列做了类型转换,跟做了运算一样,索引失效。
这就是为什么我见过无数人在phone字段上建了索引,查询还是慢成狗的真正原因。
解决方法?简单:
WHERE phone = "13800138000" -- 字符串字面量
加个引号,世界和平。
还有更阴的——函数包裹
这种情况更隐蔽:
WHERE DATE(created_at) = '2026-06-01'
created_at是DATETIME,你用DATE()函数包了一层。数据库看到这个,脑子里只有一个想法:
我排好序的是完整的时间戳,你给我的却是一个日期。我怎么知道这个日期对应哪些时间?
所以——索引列被函数包裹,索引必失效。
正确写法:
WHERE created_at >= '2026-06-01 00:00:00' AND created_at < '2026-06-02 00:00:00'
或者:
WHERE created_at BETWEEN '2026-06-01 00:00:00' AND '2026-01 23:59:59'
虽然长一点,但是能走索引,值不值?
最离谱的:OR语句
看这个:
WHERE name = "张三" OR age = 25
假设name和age都有索引,这条SQL会怎么走?
答案是:只有name的索引生效,age的索引被忽略。
因为OR语句要求两个条件都走索引,才能优化成索引合并。只要有一个条件不走索引,整个查询就只能用另一个索引,或者全表扫描。
解决方法?UNION:
SELECT * FROM users WHERE name = "张三"
UNION
SELECT * FROM users WHERE age = 25;
或者把OR改成UNION ALL加去重,根据你的业务场景选。
说点真正重要的
讲了这么多,有人可能会问:你说的这些我都知道了,有没有更系统的判断方法?
有。每次写完SQL,先跑一下EXPLAIN或者EXPLAIN ANALYZE,看看type列是不是ALL,key列是不是NULL。
如果type是ALL而且key是NULL——恭喜你,你的查询正在全表扫描。
还有几个我踩过坑的经验:
- LIKE以通配符开头,如LIKE '%keyword',索引必失效
- !=和NOT IN,大多数情况下不走索引
- 隐式类型转换,字符串字段用数字查、数字字段用字符串查
- 联合索引不遵循最左前缀,直接查第二列
最后说两句
加索引不是什么高深技术,每个CRUD仔都会。但理解索引什么时候失效、为什么会失效,才是真正考验功力的地方。
很多人以为性能问题是玄学,其实只是因为不了解底层原理。
下次数据库慢了,先别急着加索引,用EXPLAIN看看这条SQL到底在干什么。
说不定你就省下了改代码、加硬件的好几轮扯皮。
毕竟——
老板要的是结果,不是你加了几个索引。