explain必须在mysql客户端手动执行才能准确判断索引是否生效,因db::getlastsql()仅返回sql字符串而不含执行计划;需重点观察type(all为全表扫描)、key(null表示未用索引)及最左前缀匹配规则。

EXPLAIN 必须在开发环境手动执行,不能只看 getLastSql()
ThinkPHP 的 Db::getLastSql() 只返回拼出来的 SQL 字符串,不包含执行计划。索引是否生效,得靠 MySQL 自己的 EXPLAIN 输出判断。直接在 MySQL 客户端或 phpMyAdmin 里粘贴那条 SQL 并加 EXPLAIN 前缀,是最准的方式。
常见错误现象:
- 模型写了
where(['status' => 1, 'type' => 2]),但响应慢,getLastSql()看着没问题,实际没走索引 - 开启了
'sql_explain' => true配置,但只对 SELECT 生效,INSERT/UPDATE 不触发,误以为“已覆盖全部场景”
实操建议:
- 把
Db::name('user')->where('mobile', $phone)->find()生成的 SQL 拿出来,在 MySQL 中执行EXPLAIN SELECT * FROM user WHERE mobile = '13800138000' - 重点盯
type列:值为ALL表示全表扫描,range或ref才算用了索引 -
key列为空(NULL)说明优化器压根没选索引,哪怕你建了也没用
联合索引失效的典型顺序陷阱
复合索引 (status, type, created_at) 不是“任意字段组合都能用”,它严格依赖最左前缀匹配。ThinkPHP 的 where 条件顺序写错,MySQL 就会跳过整个索引。
使用场景举例:
- ✅
where(['status' => 1, 'type' => 2])→ 匹配前两列,走索引 - ❌
where(['type' => 2])→ 缺少status,跳过最左列,索引失效 - ⚠️
where(['status' => ['>', 1], 'type' => 2])→status是范围查询,type列无法用于索引查找,只用到status
注意:order 和 limit 也受此约束。比如 ->order('type desc') 在上面的联合索引中不会加速,因为 type 不在等值条件之后连续位置。
函数操作和模糊查询让索引彻底失效
只要在 WHERE 条件里对索引字段做了计算或转换,B+ 树就无法直接比对,只能退化成全表扫描。
常见失效写法:
-
whereRaw('DATE(created_at) = "2024-01-01"')→ 函数包裹,索引失效 -
where('name', 'like', '%abc')→ 左模糊,无法从索引头开始匹配 -
where('mobile', 'like', '138%')→ 右模糊,可以走索引,但要注意字段长度和前缀索引设置
正确替代方案:
- 用
whereBetween('created_at', [$start, $end])替代DATE()函数 - 左模糊需求改用全文索引(
FULLTEXT)或 Elasticsearch,别硬扛 - 如果必须用
LIKE,确保字段有索引且模式是'abc%',同时检查EXPLAIN的key_len是否合理
NULL 值和联合唯一索引的隐性坑
MySQL 中,联合唯一索引对 NULL 值的处理很特殊:多个 NULL 被视为“不相等”,所以 (user_id, sku_id) 联合唯一时,(1, NULL) 和 (1, NULL) 不冲突——这会导致业务上认为“重复”的数据被插入成功。
容易踩的坑:
- Excel 导入时某字段为空,PHP 写入数据库变成
NULL,联合索引形同虚设 -
where(['user_id' => 1, 'sku_id' => null])查询不到数据,因为NULL不能用=判断,得用IS NULL - 用
count()做唯一校验时,where(['a' => $a, 'b' => $b])->count()如果$b是null,查不到记录,但数据库仍允许插入另一条(a=1, b=NULL)
解决思路:
- 字段设计阶段就明确是否允许
NULL,不允许的设为NOT NULL DEFAULT '' - 联合唯一校验逻辑里,对可能为
NULL的字段单独处理,例如用whereRaw('(a = ? AND (b = ? OR (b IS NULL AND ? IS NULL)))', [$a, $b, $b]) - 导入前统一清洗空值,避免
NULL混入联合键
真正卡住性能的,往往不是没建索引,而是建了却因顺序、NULL、函数或模糊方式不对而完全失效。每次加索引后,务必用 EXPLAIN 看一眼 key 和 type,而不是只信 PHP 层的日志或直觉。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











