90%的慢查询主因是PHP侧SQL写法不当、索引未匹配、连接未复用或缓存缺失;EXPLAIN显示“Using where; Using filesort”却未走索引,源于函数包裹字段(如WHERE DATE(created_at)=...)破坏B+树有序性,须改用范围查询。

直接说结论:90% 的慢查询不是数据库不行,而是 PHP 侧没管住 SQL 的写法、索引没对上、连接反复重建、或者该缓存的硬查库。
为什么 EXPLAIN 显示“Using where; Using filesort”却没走索引
这是最典型的“以为建了索引就万事大吉”陷阱。MySQL 不会自动猜你想要什么顺序,也不会在字段被函数包裹时用索引。
-
WHERE DATE(created_at) = '2025-04-01'→ 索引完全失效,必须改成WHERE created_at >= '2025-04-01 00:00:00' AND created_at -
ORDER BY status, created_at却只给created_at建了单列索引 → 必须建复合索引idx_status_created_at (status, created_at),且字段顺序不能颠倒 -
LIKE '%关键词'→ B-tree 索引无法前导匹配,要么改用全文索引(FULLTEXT),要么交给 Elasticsearch
PHP 里怎么避免 N+1 查询和循环中执行 SQL
常见于列表页渲染用户头像、分类名、状态文本等场景,一个页面查出 50 条记录,再循环 50 次查关联数据,实际发出 51 条 SQL。
- 用
JOIN一次性拉取:比如查文章列表带作者名,别在循环里SELECT name FROM users WHERE id = ?,改写为SELECT a.id, a.title, u.name FROM articles a JOIN users u ON a.user_id = u.id - 用
IN批量查关联数据:先收集所有user_id数组,再SELECT id, name FROM users WHERE id IN (1,5,8,12,...),注意 MySQL 默认max_allowed_packet限制,超长需分批 - 用
fetchAll()代替多次fetch():一次取完结果集,PHP 层做映射,别边 fetch 边查下一条
PDO 连接和预处理哪些配置真能提速
默认 PDO 配置是“安全优先”,不是“性能优先”。几个关键开关不打开,持久连接和预处理都白搭。
- 必须关掉模拟预处理:
PDO::ATTR_EMULATE_PREPARES => false,否则 MySQL 不缓存执行计划,每次execute()都重新解析 SQL - 开启持久连接:
PDO::ATTR_PERSISTENT => true,但要注意连接泄漏风险——确保脚本结束前没遗留未关闭的事务或游标 - 批量插入别拼字符串:
INSERT INTO t (a,b) VALUES (1,2),(3,4),(5,6)比 3 次单条INSERT快 3–5 倍;用prepare()+ 循环execute()也比字符串拼接安全
缓存键怎么设才不会脏、又不至于太短命
缓存不是加个 set('sql_abc123', $data) 就完事。键设计不当,要么永远不更新(脏数据),要么一写就失效(缓存形同虚设)。
- 键名建议包含:SQL 模板哈希 + 参数签名(如 MD5(serialize([$user_id, $status]))),而不是原始 SQL 字符串(含空格/换行易变)
- 不要依赖 TTL “等它过期”,关键数据变更时主动删缓存:
DELETE FROM cache WHERE key LIKE 'user_profile_%'或用 Redis 的DEL user_profile_123 - 对统计类查询(如“本月订单数”),别缓存结果值,改缓存“最后更新时间”,PHP 层判断是否超 5 分钟再重算
最容易被忽略的是:索引不是建完就一劳永逸。业务逻辑变了、查询条件加了新字段、WHERE 和 ORDER BY 组合变了,旧索引可能立刻变拖累。定期用慢查询日志 + EXPLAIN 回检,比盲目加索引有用十倍。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











