pdo性能取决于连接管理、sql写法、预处理方式、错误处理及mysql配置;应启用持久连接、复用连接对象、按场景合理使用预处理、指定高效fetch模式、设errmode_exception并配合日志分析。

PHP PDO 本身不决定性能上限,真正影响压测结果的是连接管理、SQL 写法、预处理使用方式、错误处理策略以及底层 MySQL 配置。一次真实的压测,往往暴露的是应用层设计问题,而非 PDO 慢。
连接复用比“用完就关”更关键
PDO 默认是短连接,每次 new PDO() 都会建立新 TCP 连接,高并发下容易打满连接数或触发三次握手延迟。生产环境必须启用持久连接(PDO::ATTR_PERSISTENT),但要注意:
- 持久连接由 PHP-FPM 进程持有,不能在脚本结束时主动 close,需依赖进程回收
- MySQL 的 wait_timeout 要大于 PHP-FPM 的 max_request 或 idle timeout,否则连接被服务端断开后,PDO 不会自动重连,下次 query 直接报错
- 不要在循环里反复 new PDO,应全局单例或容器注入,连接对象复用到底层语句执行
预处理不是万能的,要分场景用
prepare + execute 确实防 SQL 注入且能复用执行计划,但并非所有查询都适合:
- 简单 SELECT id FROM user WHERE id = ?(主键等值)——预处理收益明显,MySQL 可缓存执行计划
- SELECT * FROM log WHERE created_at > ? ORDER BY id DESC LIMIT ?, ? ——带 LIMIT 和动态偏移的分页,预处理无法避免全表扫描,重点应是加索引和优化分页逻辑
- INSERT INTO t (a,b,c) VALUES (?,?,?) ——批量插入时,应改用 INSERT ... VALUES (...),(...),(...) 单条语句 + execute(array_merge(...)),比循环 execute 快 3–5 倍
fetch 模式直接影响内存与速度
默认 PDO::FETCH_BOTH 同时返回数字索引和关联键,内存翻倍且解析慢。压测中应显式指定:
立即学习“PHP免费学习笔记(深入)”;
- 只读字段名?用 PDO::FETCH_ASSOC(最常用)
- 只按顺序取值?用 PDO::FETCH_NUM(最快,尤其配合 list() 解构)
- 查单行单字段(如 COUNT(*))?直接 fetchColumn(),避免构造数组开销
- 大量数据导出?禁用 fetchAll(),改用 fetch() 循环 + unset() 中间变量,防止 OOM
错误模式别设成 SILENT
压测期间若设 PDO::ATTR_ERRMODE = PDO::ERRMODE_SILENT,SQL 报错会被吞掉,只返回 false,极易掩盖死锁、超时、主从延迟导致的脏读等问题。正确做法:
- 开发/压测环境统一设为 PDO::ERRMODE_EXCEPTION,让异常抛出,配合日志记录完整 SQL 和绑定参数
- 对明确可预期的失败(如用户不存在),用 try/catch 包裹,不要依赖 false 判断
- 开启 MySQL general_log 或 slow_query_log,交叉验证 PDO 执行的 SQL 是否真被发出、是否被优化器改写
不复杂但容易忽略。压测不是比谁 QPS 高,而是看在目标并发下,平均延时稳不稳定、错误率有没有突增、数据库负载是否均衡。PDO 是工具,用对了,它不会拖后腿。











