必须用explain对比加索引前后执行计划:type需从all变为ref/range,key显示新建索引名,rows显著下降;联合索引字段顺序须等值条件在前、范围条件在后;子查询索引需单独验证;冗余索引(如index(a)与index(a,b))应删除。

直接用 EXPLAIN 对比加索引前后的执行计划
不看 EXPLAIN 输出,就等于闭眼调优。你改了索引,但 type 还是 ALL,rows 没降,说明压根没生效。必须在 phpMyAdmin 的 SQL 标签页里,对同一查询语句分别执行:
-
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'paid';(加索引前) -
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'paid';(建完INDEX(user_id, status)后)
重点比三列:type(要从 ALL 变成 ref 或 range)、key(是否显示你刚建的索引名)、rows(扫描行数是否明显下降)。别只看“用了索引”,得看它到底帮你跳过了多少行。
联合索引字段顺序错了,EXPLAIN 会假装正常
比如你为 WHERE category_id = 5 AND created_at > '2025-01-01' 创建了 INDEX(created_at, category_id),EXPLAIN 仍可能显示 key 有值、type 是 range——但它只利用了 created_at 部分,category_id 实际是过滤后扫描,不是索引查找。正确顺序应是 INDEX(category_id, created_at),因为等值条件字段必须放最左。
- 等值条件(
=、IN)字段优先靠左 - 范围条件(
>、BETWEEN、LIKE 'abc%')只能放最后一位,且之后字段无法走索引 -
ORDER BY字段若需避免Using filesort,也得纳入联合索引并保持顺序一致
EXISTS 子查询的索引必须单独验
Laravel 的 whereHas('posts') 生成的 SQL 里,主表 users 可能走了索引,但子查询 SELECT 1 FROM posts WHERE posts.user_id = users.id 如果没在 posts.user_id 上建索引,就会全表扫描——而这个代价被 EXPLAIN 主查询的 rows 完全覆盖,你看不到。
- 把子查询单独拎出来,在 phpMyAdmin 里执行
EXPLAIN SELECT 1 FROM posts WHERE user_id = 123; - 确认它的
type是ref或const,key显示对应索引 - 如果子查询里还有
AND status = 'published',那索引就得是INDEX(user_id, status),不能只建单列user_id
索引不是越多越好,冗余索引会拖慢写操作
phpMyAdmin 的“索引”标签页里,如果看到 INDEX(a) 和 INDEX(a, b) 同时存在,前者就是冗余的——后者完全能覆盖前者的查询能力。这种冗余不仅浪费磁盘空间,还会让 INSERT/UPDATE/DELETE 更慢,因为每条写操作都要维护多个索引树。
- 用 phpMyAdmin 执行
SHOW INDEX FROM your_table;查看所有索引 - 识别前缀重复的联合索引:例如
INDEX(user_id)和INDEX(user_id, team_id)→ 删掉前者 - 删除前先确认没有业务 SQL 显式依赖该单列索引(比如
WHERE user_id = ? ORDER BY id这类排序场景有时会意外依赖单列索引)
真正卡住人的,往往不是“要不要加索引”,而是“加在哪几个字段上、按什么顺序、删掉哪些旧的”。EXPLAIN 是唯一能验证你直觉是否正确的工具,其他全是猜测。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











