SELECT查询慢八成因索引未用对;WHERE字段无索引必致全表扫描,应优先为高频过滤列建索引,复合索引须遵循最左前缀原则,EXPLAIN显示type=ALL即未走索引,隐式转换、函数操作、OR含非索引列等均会导致失效。

直接说结论:SELECT 查询慢,八成是因为没用对索引,而不是语句本身写得差。建错、建多、建了不用,比不建更麻烦。
WHERE 条件列没索引,基本等于裸奔
数据库遇到 WHERE user_id = 123 这种查询,如果 user_id 没索引,就会扫全表——哪怕只想要 1 行,也要读完几百万行。这不是“慢”,是“必然慢”。
- 优先给
WHERE中高频出现的列建索引,比如status、created_at、order_no - 别只看单列:如果常写
WHERE status = 'paid' AND created_at > '2025-01-01',那就该建复合索引CREATE INDEX idx_status_created ON orders(status, created_at) - 注意最左前缀:这个复合索引能加速
WHERE status = 'paid'或WHERE status = 'paid' AND created_at > ...,但对WHERE created_at > ...单独用无效
EXPLAIN 显示 type=ALL,说明索引完全没被用上
EXPLAIN SELECT * FROM users WHERE email = 'a@b.com'; 如果返回结果里 type 是 ALL,就代表数据库放弃了索引,硬刚全表扫描。常见原因有:
-
email列类型是VARCHAR,但查询时传了数字或带空格的字符串,触发隐式类型转换,索引失效 - 在条件里对索引列用了函数,比如
WHERE UPPER(email) = 'A@B.COM',哪怕email有索引也白搭 - 索引列允许
NULL,而查询写了WHERE email IS NOT NULL,某些旧版本 MySQL 可能不走索引 - 统计信息过期:
ANALYZE TABLE users;强制刷新后,EXPLAIN结果可能立刻变好
ORDER BY 和 GROUP BY 用不上索引,排序/聚合就成瓶颈
比如 SELECT * FROM logs ORDER BY created_at DESC LIMIT 10,如果 created_at 没索引,数据库得先把几十万行读出来再内存排序——OOM 风险高,延迟飙升。
-
ORDER BY的列必须和索引顺序严格一致(方向也要匹配,如索引是(a ASC, b DESC),那ORDER BY a ASC, b DESC才能用上) -
GROUP BY同理,且尽量避免SELECT *+GROUP BY,因为非分组字段数据库要随机取值,容易触发临时表和文件排序 - 覆盖索引能绕过回表:如果建了
INDEX idx_uid_status ON users(user_id, status),那SELECT user_id, status FROM users WHERE status = 'active'就不需要再查原表数据,直接从索引里拿完事
真正难的不是“怎么建索引”,而是判断“哪条查询值得建、建什么、建几个”。一个 WHERE 条件带三个字段的查询,建单列索引还是三列复合索引?要看实际执行频率、数据分布、写入压力——这些没法靠模板解决,只能靠 EXPLAIN 看、SHOW INDEX 查、线上慢日志盯。索引不是配置项,是持续演进的决策。

















