type=all表示mysql正在全表扫描,是性能严重隐患,需立即检查索引是否存在、是否被正确使用,尤其关注where条件字段的索引覆盖、最左前缀原则及避免函数/隐式转换导致索引失效。

SELECT * 会拖慢查询,索引建错或没建会让 WHERE 变全表扫描,JOIN 字段类型不一致或缺索引直接触发临时表和慢日志报警——这些不是“可能出问题”,而是线上 PHP 应用数据库响应变慢的前三名原因。
为什么 EXPLAIN 显示 type=ALL 就得马上改
这代表 MySQL 正在做全表扫描,哪怕表只有 10 万行,每秒也扛不住几十次这种查询。EXPLAIN 的 type 字段是第一眼要盯住的:从 const、ref 到 range 是健康区间,ALL 或 index 就该停下手头活儿去查索引。
- 先跑
SHOW INDEX FROM 表名,确认 WHERE 条件里的字段(比如user_id、status)真有索引,不是靠猜 - 联合索引必须严格遵循最左前缀:建了
INDEX idx_type_status (type, status),那WHERE status = 1是用不上这个索引的 -
ORDER BY created_at DESC LIMIT 10这类语句,如果created_at没索引,EXPLAIN里会出现Using filesort,意味着排序在内存/磁盘临时区完成,不是走索引有序扫描
PHP 里写 SQL 时哪些操作会让索引当场失效
不是所有带 WHERE 的语句都能走索引。函数包裹、隐式转换、OR 条件混用,都是常见“索引杀手”。
-
WHERE DATE(created_at) = '2024-01-01'→ 改成WHERE created_at >= '2024-01-01 00:00:00' AND created_at -
WHERE user_id + 0 = 123→ 直接写WHERE user_id = 123,避免数值型字段被字符串隐式转换 -
WHERE status = 1 OR is_deleted = 0→ 单独建复合索引成本高,不如拆成两个查询 + PHP 合并,或改用UNION - LIKE 开头带通配符:
LIKE '%关键词'无法用索引;LIKE '前缀%'才能走索引
用 PDO 预处理却还是慢?检查这三处配置
预处理本身不等于性能提升,它只是安全基础。真正影响执行效率的是底层连接行为与参数绑定方式。
- 必须关掉模拟预处理:
PDO::ATTR_EMULATE_PREPARES => false,否则 MySQL 不执行原生预编译,prepare/execute只是 PHP 层字符串拼接 - 持久连接不是万能的:
PDO::ATTR_PERSISTENT => true在 PHP-FPM 下效果有限,且可能引发连接泄漏;更稳妥的是用 Swoole 协程或连接池中间件 - 批量插入别用循环
execute():INSERT INTO t (a,b) VALUES (1,2),(3,4),(5,6)一条语句插 1000 行,比 1000 次单条快 10 倍以上;UPDATE/DELETE 同理,优先考虑IN或JOIN批量操作
缓存不是加个 Redis 就完事,键设计错了照样穿透数据库
缓存命中的前提是键能准确反映查询逻辑。同一张表、不同条件、不同字段组合,必须生成唯一且可预测的缓存键。
- 不要用原始 SQL 当 key:
"SELECT id,name FROM users WHERE status=1"容易因空格、换行、大小写不一致导致重复缓存 - 推荐用结构化签名:
"users:status:1:fields:id,name",参数部分做md5(serialize($params))更稳妥 - 写操作后必须删缓存,不是更新:比如用户资料变更,删掉
"user:123"和"users:status:1:*"这类前缀键,避免脏数据;用 Redis 的DEL或SCAN+DEL清理,别依赖过期自动淘汰 - 分页列表缓存尤其危险:用游标(cursor)代替
LIMIT offset, size,把上一页最后一条的id作为下一页起点,缓存键变成"articles:cursor:12345:limit:20",避免深度分页击穿
EXPLAIN 看着走了索引,但 rows 显示扫描了 80% 的数据——这些细节不抠到执行计划里,性能瓶颈就一直在那里。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











