90%的慢查询源于where字段未建索引,需用explain验证索引命中情况;mobile等单字段加普通索引,status+created_at等复合条件建联合索引(等值在前、范围在后);关联外键、分页子查询、pdo预编译等均需对应索引优化。

WHERE条件字段没建索引,90%的慢查询根源在这里
ThinkPHP执行SQL慢,最常见、最被忽视的原因是WHERE里用的字段根本没索引。比如Db::table('user')->where('mobile', $phone)->find()跑得慢,不是TP的问题,而是mobile字段没加索引,MySQL只能全表扫描。
实操建议:
- 先查索引:
SHOW INDEX FROM user,确认mobile是否在输出列表中 - 没索引就加:
ALTER TABLE user ADD INDEX idx_mobile (mobile) - 复合条件(如
status = 1 AND created_at >= ?)优先建联合索引,顺序必须是等值字段在前、范围字段在后:ADD INDEX idx_status_ctime (status, created_at) - 避免函数操作:写
where('DATE(created_at)', '2024-01-01')会让索引失效;改用whereBetween('created_at', [$start, $end])
关联查询外键不建索引,with()再快也白搭
with('profile')本身不慢,但profiles.user_id没索引时,JOIN或子查询会触发profiles表全表扫描——EXPLAIN里type显示ALL就是铁证。
实操建议:
- 主表
users.id有主键索引 ✔️,但关联表profiles.user_id必须单独建索引 ❌→ 补上ALTER TABLE profiles ADD INDEX idx_user_id (user_id) - 如果
whereHas('posts', function ($q) { $q->where('status', 1); }),那posts.user_id和posts.status都要进同一个联合索引:ADD INDEX idx_user_status (user_id, status) - 建完立刻验证:
EXPLAIN SELECT * FROM profiles WHERE user_id = 123,看key列是否命中刚建的索引
LIMIT offset, size翻页越往后越卡?子查询+覆盖索引才是解法
LIMIT 500000, 20慢,是因为MySQL必须从头扫描并跳过50万行。ThinkPHP的paginate()默认就生成这种SQL,数据量一过百万,第500页基本超时。
实操建议:
- 改用子查询先取ID:
SELECT t.* FROM article t INNER JOIN (SELECT id FROM article WHERE status = 1 ORDER BY id DESC LIMIT 500000, 20) tmp ON t.id = tmp.id - 这个子查询要快,得靠覆盖索引:比如按
create_time分页,就建ADD INDEX idx_status_ctime_id (status, create_time DESC, id),确保SELECT id完全走索引不回表 - ThinkPHP 5.1/6.0 中不要硬拼SQL,用
Db::query()执行该语句,避开ORM自动注入干扰 - 注意字段顺序:等值条件(
status)必须在前,排序字段(create_time)居中,被SELECT的字段(id)放最后
预编译不是自动开的,手动PDO才能真正复用执行计划
Db::table()->where()->select()底层是字符串拼接SQL,每次都要解析、生成执行计划。高并发下,这部分开销远超数据库本身耗时。TP不会自动启用PDO预编译。
实操建议:
- 绕过Query类,直连PDO:
$pdo = Db::connect()->getPdo() - 手动prepare固定结构SQL:
$stmt = $pdo->prepare('SELECT * FROM user WHERE mobile = ? AND status = ?') - execute传参:
$stmt->execute([$phone, 1]),再fetchAll() - 关键限制:SQL结构必须稳定——不能动态拼
ORDER BY或LIMIT,否则PDO无法复用执行计划,反而更慢
索引是否生效,不看TP日志,只看MySQL的EXPLAIN输出;而EXPLAIN结果里key为空、rows远大于实际返回数、Extra出现Using filesort,这些细节比“有没有加索引”更关键。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











