WebPageTest瀑布图中的Wait时间过长:后端瓶颈排查手册
Wait时间长,说明服务器”收到请求”和”开始吐数据”之间,有什么东西在拖后腿。
这段时间在瀑布图里是黄绿色的那一块,肉眼可见。它和网络传输无关,和物理距离无关——CDN已经接了还是慢,十有八九就是这段出了问题。

webpagetest
先搞清楚Wait时间在测什么
Wait时间 = 请求到达服务器之后,服务器开始生成响应之前所消耗的时间。 包含这几个环节:
- 服务器接收请求、分配PHP进程
- PHP执行脚本、调用数据库
- 数据库查询、返回结果
- PHP渲染HTML、准备输出
任何一个环节卡住,Wait就长。问题是卡在哪里,瀑布图本身不告诉你——它只给了一个结果数字,根因要靠额外手段去挖。
排查顺序要按概率来,别乱撒网。
第一排查:数据库查询——Wait高的头号嫌疑
没有索引的查询、N+1查询问题、数据量大的全表扫描——这三类数据库问题占了Wait过高原因的一大半。

wordpress
WordPress站怎么查
装 Query Monitor 插件,打开任意一个页面,右上角会出现一个悬浮条。点开它,能看到:
- 当前页面一共发起了多少条SQL查询
- 哪几条最慢(单位:毫秒)
- 是哪个插件或主题文件触发的
正常的产品页面,数据库查询控制在30条以内是比较健康的状态。如果你看到80条、120条,那基本就是Wait长的根源。
常见的罪犯:WooCommerce叠加多个第三方插件,每个插件各自发几条查询,叠起来就爆了。
用EXPLAIN看查询执行计划
发现慢查询之后,把那条SQL在数据库控制台里跑一遍 EXPLAIN:
sqlEXPLAIN SELECT * FROM wp_posts WHERE post_status = 'publish' ...
重点看 type 列:
ALL= 全表扫描,危险信号,说明没走索引ref/eq_ref= 走了索引,正常rows列的数字代表扫描了多少行,几十万行是警报
没有索引的字段加上索引之后,同一条查询从几百毫秒降到几毫秒是完全可能的。这个优化的性价比极高。
第二排查:PHP执行效率——OPcache没开或者代码本身有问题
PHP每次执行脚本都要重新解析、编译,如果OPcache没开,这个成本在每次请求里都要重复支付。
验证OPcache有没有开很简单,在服务器上建一个 phpinfo.php 文件,搜索 opcache.enable,看值是 On 还是 Off。
如果是 Off,这是整个优化链里成本最低、效果最直接的一步。改 php.ini 加四行配置(上一篇已经写了),重启PHP-FPM,Wait时间通常能砍掉50-100ms。
除了OPcache,还有一类更隐蔽的PHP问题:同步调用外部API。
这个我踩过,也见客户踩过。某个插件在页面渲染时发起一个HTTP请求去外部服务取数据——汇率、库存、天气、地图——如果那个外部API响应慢,你的页面就只能等着。
怎么发现?在 Query Monitor 里有一个”HTTP API Calls”标签,能看到页面加载过程中发起了哪些外部HTTP请求、各耗时多少。一眼就能揪出来。
第三排查:服务器资源——CPU和内存被打满了
如果平时Wait正常,某个时段突然变长,大概率是服务器资源在那段时间被耗尽。
共享主机用户对这个问题最没有控制权——隔壁网站突然跑了个大任务,你的资源就被挤占了,Wait跟着涨,但你什么都没改。
检查方法:
- VPS用户:SSH进去跑
top或htop,看CPU和内存使用率 - 如果CPU长期超过80%:要么代码有死循环类问题,要么配置真的不够了
- 内存不够触发Swap:磁盘IO参与进来,速度断崖式下跌,Wait可以从200ms暴涨到5秒以上
共享主机有这个问题的话,解决办法只有两个:升级到VPS,或者换一家不过度超售的主机商。没有第三条路。
第四排查:连接池耗尽——高并发下的Wait陷阱
这个问题在低流量时不会出现,往往在做广告投放、产品上了某个媒体、展会之后突然访问量上来时才冒头。
数据库连接池有上限。并发请求超过连接池容量,后来的请求只能排队等前面的连接释放。 Wait时间在正常值的基础上,每个在排队的请求额外叠加一段等待时间。
WordPress默认的 wp-config.php 里没有做连接池管理,是靠MySQL的 max_connections 参数控制的。默认值通常是100-150,如果你的主机配置低、并发上来了,连接池就会撑爆。
查一下MySQL的当前连接数:
sqlSHOW STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections';
如果 Threads_connected 经常接近 max_connections,说明连接池是瓶颈。适当提高 max_connections,同时配合对象缓存(Redis或Memcached)减少数据库查询频率,才是真正的解法。
第五排查:wp_options表的autoload垃圾数据
这个专门针对WordPress,但效果出人意料地显著,很多人不知道。
WordPress每次加载页面,都会把 wp_options 表里所有 autoload=yes 的记录一次性读入内存。 如果这张表里堆了几千条插件遗留的垃圾数据,这个初始化过程本身就要消耗几十毫秒。
查一下你的autoload数据量:
sqlSELECT COUNT(*) FROM wp_options WHERE autoload = 'yes'; SELECT SUM(LENGTH(option_value)) / 1024 / 1024 AS total_mb FROM wp_options WHERE autoload = 'yes';
超过500条、总体积超过1MB就要清理了。用 WP-Optimize 插件可以安全清理,或者手动识别已停用插件留下的孤儿记录,直接DELETE掉。
去年帮一个做家居外贸的客户做技术审计时,他们的wp_options autoload数据累积到了4.7MB,光这一项优化完,Wait时间从680ms降到了410ms,什么其他事情都没做。这类案例在外贸网站建设项目里其实挺常见,很多网站跑了两三年,没人打扫过”屋子”。这也是厦门创意互动在做年度技术复盘时,固定会检查的一个项目。
排查优先级汇总
按从高到低的概率排:
- 数据库查询——Query Monitor拿到慢查询名单,
EXPLAIN分析索引情况 - OPcache状态——30秒内能确认,没开立即开
- 外部API同步调用——Query Monitor的HTTP Calls标签,找阻塞请求
wp_optionsautoload数据量——一条SQL查出来,超标就清- 服务器资源(CPU/内存)——
htop确认,持续超载考虑升配 - 数据库连接池——高并发场景下才会触发,先排前五项
Wait时间的排查有时候像剥洋葱,解决一个问题之后,数值降了但还不够理想,再挖一层又发现另一个问题。这是正常的——大多数线上网站都是多个瓶颈同时存在,只是严重程度不同。
先把最重的那块砍掉,再看下一个数字,一步步来,比想着一次全部搞定要靠谱得多。如果拿着Query Monitor的报告不知道从哪下刀,欢迎来聊。






