php本身没有“编程索引”概念,真正需掌握的是数据库索引在php应用中的落地实践:确保sql查询有效使用索引,避免因php拼接不当导致索引失效,核心是结合explain分析并闭环验证。

直接说结论:PHP 本身没有“编程索引”这个概念,你真正要学的,是数据库索引在 PHP 应用中的落地实践——即怎么在写 PHP 代码时,让 SQL 查询真正用上索引、不踩坑、不白加。
别被“PHP索引教程”这类标题带偏。PHP 不管索引,MySQL/SQLite 才管;PHP 只负责拼对 SQL、传对参数、别把索引干失效。
WHERE 字段没索引,PHP 写得再漂亮也全表扫
常见错误现象:type=ALL 出现在 EXPLAIN 结果里,查询耗时从几毫秒飙到几秒。
使用场景:ThinkPHP 的 where('user_id', 1)、Laravel 的 where('status', 'paid')、原生 PDO 的 $stmt->execute([1])。
实操建议:
- 先确认字段是否真有索引:
SHOW INDEX FROM users; - 低区分度字段(如
status只有 0/1)单独建索引几乎无效,别浪费 - 高频组合条件(如
where('status', 'paid')->where('created_at', '>=', $date))必须建复合索引,顺序按 WHERE 出现顺序对齐:ALTER TABLE orders ADD INDEX idx_status_created (status, created_at); - ThinkPHP 迁移中写:
$table->index(['status', 'created_at'])->execute();,字段顺序不能颠倒
PHP 拼 SQL 时一不小心就让索引失效
常见错误现象:明明加了索引,EXPLAIN 显示 key=NULL 或 key_len 比预期小很多。
原因集中在 PHP 构造 WHERE 条件的方式:
- 用函数包裹索引字段:ThinkPHP 写
whereRaw('DATE(created_at) = ?', [$date])→ 改成whereBetween('created_at', [$start, $end]) - 隐式类型转换:数据库字段是
VARCHAR,PHP 却传整数 ID:where('order_sn', 12345)→ 改为字符串:where('order_sn', '12345') - LIKE 前置通配:
where('title', 'like', '%php%')→ 无法走 B-Tree 索引;要么改前缀匹配'php%',要么换MATCH(title) AGAINST() - 范围查询放联合索引左边:
INDEX (a, b, c),却写WHERE b > 10 AND a = 1→ 实际只用到a,b和c失效
关联查询慢,不是没索引,是 PHP 加载方式错了
常见错误现象:加了 user_id 索引,with('orders') 仍卡顿;EXPLAIN 显示 Using temporary 或 rows 是主表的几倍。
根本问题:PHP 框架的预加载机制(如 Laravel with()、ThinkPHP with())在大数据量下会生成超长 IN 列表,或触发多次查询+PHP 合并,完全绕过数据库优化能力。
实操建议:
- 关联字段(如
orders.user_id)必须有索引,且要是单列索引或联合索引最左字段 - 主表结果 ≥ 500 行时,放弃
with(),改用join()+selectRaw()一次查完 - ThinkPHP 中避免
with('profile.address')这种三级嵌套,会发 3 条 SQL;拆成两步或手写 JOIN - Laravel 大列表分页慎用
withCount()+with()组合,withCount()本身是子查询,叠加后易出Using filesort
EXPLAIN 看不懂,等于没优化
很多 PHP 开发者跳过这步,靠“感觉”加索引,结果加了一堆没用的。
关键字段必须盯紧:
-
type:ALL(全表扫)、index(全索引扫)危险;range、ref、const较健康 -
key:显示实际使用的索引名,NULL就是没走索引 -
key_len:值越小说明命中索引字段越少,比如idx_a_b_c上只用了a,key_len就远小于理论最大值 -
rows:MySQL 预估扫描行数,接近总行数≈失效 -
Extra:出现Using filesort(ORDER BY 没走索引)、Using temporary(GROUP BY 或复杂 JOIN)、Using where; Using index(覆盖索引,理想状态)
ThinkPHP 获取原始 SQL:加 ->fetchSql(true);Laravel 用 DB::enableQueryLog() + DB::getQueryLog();然后拿去 MySQL 客户端执行 EXPLAIN FORMAT=JSON。
真正的难点不在“怎么加索引”,而在于:每次改一个 PHP 查询逻辑,都要重新跑 EXPLAIN,看它到底用了什么、没用什么、为什么没用——这个闭环不建立,所有索引都是赌运气。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











