要确认sql是否走索引,必须用getlastsql()获取带真实参数的语句并加explain执行,重点检查type不为all、key不为null、rows接近实际返回行数。

怎么确认SQL到底走没走索引
别信 buildSql() 或日志里拼出来的 SQL,它没带真实参数,根本看不出索引用没用上。真正要验证,得靠 getLastSql() 拿到已替换参数的完整语句,再手动加 EXPLAIN 执行。
重点关注三件事:type 不能是 ALL(全表扫描),key 不能是 NULL(说明压根没用索引),rows 要接近你实际返回的行数——比如查 10 条却扫了 5 万行,那肯定有问题。
- ThinkPHP 的
where(['status'=>1, 'score'=>['>', 80]])看似用了两个字段,但范围条件(score > 80)后面的字段无法利用单列索引,必须建(status, score)复合索引才有效 -
where('name', 'like', '%abc')是左模糊,B+ 树没法前缀匹配,key必为NULL;应改用where('name', 'like', 'abc%')或上全文索引 -
whereRaw('DATE(create_time) = "2024-01-01"')对字段套函数,索引直接失效;得写成whereBetween('create_time', ['2024-01-01 00:00:00', '2024-01-01 23:59:59'])
为什么 SELECT * 在 PHP 8.5.5 里更危险
PHP 8.5.5 对内存管理和字符串解析做了微调,宽表 + 大字段(比如 TEXT、JSON)时,SELECT * 容易触发 MySQL 临时磁盘表,同时 PHP 还得多解析几十 KB 数据,拖慢整个请求生命周期。
哪怕你只用 $user['name'],MySQL 仍会把整行数据序列化传给 PDO,网络传输、内存分配、结果集解析全在多干活。
- 主查询必须显式指定字段:
field('id,name,avatar,status'),别留空或依赖默认 - 列表页尤其要避开
content、description这类大字段,它们常是性能拐点 - 关联查询时,
JOIN的字段也要收敛,别让从表也SELECT *
怎么干掉 N+1 查询
循环里查数据库是 PHP 8.5.5 下最典型的性能杀手——不是语法错,是结构错。每次 query() 都有连接复用开销、SQL 解析、执行计划生成、网络往返,叠加起来比单次 IN 或 JOIN 慢 3–10 倍。
反例:foreach ($ids as $id) { $db->query("SELECT title, content FROM article WHERE id = $id"); }
- 正解 1(批量 IN):
$db->query("SELECT id, title FROM article WHERE id IN (" . implode(',', $ids) . ")"),注意$ids必须是整型且已过滤,否则要用预处理绑定 - 正解 2(JOIN):把循环逻辑提前合并进主查询,用
LEFT JOIN一次性拉取关联数据 - 正解 3(预处理重用):如果必须循环,把
prepare()移到循环外,循环内只做bind_param()和execute()
哪些索引操作在 PHP 8.5.5 里容易被忽略
PHP 8.5.5 本身不改索引逻辑,但它的错误修复和底层优化会让某些“看似能跑”的低效写法暴露得更早——比如隐式类型转换导致的全表扫描,在旧版本可能侥幸命中缓存,新版本更容易直接卡住。
- 字段是
VARCHAR,却传整型:where('mobile', 13800001234)→ MySQL 强转触发全表扫描;必须统一为字符串:where('mobile', '13800001234') - 复合索引顺序必须匹配查询条件最左前缀:
(a,b,c)支持WHERE a=1 AND b=2,但不支持WHERE b=2 AND c=3 - 单表索引总数建议控制在 5 个以内;日志类写多读少的表,加索引反而拖慢
INSERT
慢查询日志和 EXPLAIN 是唯二靠谱的判断依据,别靠感觉——PHP 8.5.5 再稳,也救不了没走索引的 SQL。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











