索引未建对导致全表扫描,应为where字段建单列或复合索引,避免函数操作、类型混用和错误通配符,关注explain中extra字段优化排序与临时表问题。

索引没建对,EXPLAIN 一跑就是 type=ALL,再快的服务器也扛不住。
WHERE 条件字段没索引,马上加
这是线上最常见、最容易被忽略的性能断点。PHP 里一个 SELECT * FROM orders WHERE user_id = ?,如果 user_id 没索引,10 万行表就等于每次查都要扫全表。
- 先确认:运行
SHOW INDEX FROM orders,看user_id是否在结果里 - 没索引就加:
ALTER TABLE orders ADD INDEX idx_user_id (user_id) - 别用
SELECT *测试——它可能掩盖索引是否真正覆盖;换成明确字段,比如SELECT id, status FROM orders WHERE user_id = 123,再EXPLAIN - 字符串字段(如邮箱)可加前缀索引节省空间:
ALTER TABLE users ADD INDEX idx_email_prefix (email(32)),但要确保前缀能区分大部分值
多条件查询必须用复合索引,单列索引基本没用
比如 PHP 中常写的 WHERE status = 'paid' AND created_at > '2026-01-01',给 status 和 created_at 各建一个单列索引,MySQL 通常只选其一,另一个条件仍走全表过滤。
- 按“等值在前、范围在后”排序建索引:
ALTER TABLE orders ADD INDEX idx_status_created (status, created_at) - 如果还带
ORDER BY id DESC,且你只查少量字段,可考虑把id加进索引末尾做成覆盖索引:idx_status_created_id (status, created_at, id) - 注意:
WHERE created_at > '2026-01-01' AND status = 'paid'这种写法顺序不影响命中,但索引字段顺序必须是(status, created_at)才能生效——MySQL 优化器会自动调整条件顺序匹配最左前缀
这些写法会让索引当场失效,PHP 代码里必须改
不是 SQL 写出来就能走索引。函数、类型混用、通配符位置不对,都会让 MySQL 直接放弃索引树查找。
-
WHERE YEAR(created_at) = 2026→ 改成WHERE created_at >= '2026-01-01' AND created_at -
WHERE user_id = '123'(字段是INT)→ 改成整型参数绑定,PDO 中确保$stmt->bindValue(':id', 123, PDO::PARAM_INT) -
WHERE name LIKE '%关键词'→ 无法用 B-tree 索引;要么改成LIKE '关键词%',要么上FULLTEXT或交给 Elasticsearch -
WHERE status = 1 OR is_deleted = 0→ 复合索引很难覆盖,不如拆成两个UNION查询,或在 PHP 层分两次查后合并
EXPLAIN 的 Extra 字段比 type 更容易被忽略
type=ref 只代表用了索引,不代表高效。真正卡顿常藏在 Extra 里:
-
Using filesort:说明ORDER BY没走索引排序,得额外排序。解决方法是让排序字段进复合索引,且不能有范围条件挡在它前面 -
Using temporary:常出现在GROUP BY或含DISTINCT的 JOIN 中,意味着建了临时表。检查关联字段是否都有索引、类型是否一致 -
Using index condition是好的,表示用了索引下推(ICP),减少回表;Using index更好,说明是覆盖索引,完全不用查数据行 - 别信缓存:加完索引后,立刻
ANALYZE TABLE orders更新统计信息,否则优化器可能还按旧数据做决策
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











