本文约 4,525 字,预计阅读 12 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:20 个插件的站比 60 个插件的站还慢
「插件不要装太多」是 WordPress 圈流传最广的建议之一,但它几乎是错的。真正决定站点速度的,从来不是插件数量这个数字,而是每个插件在每次请求里做了什么。
一个只注册了一个短代码、只在特定页面输出内容的插件,装上它对首页速度的影响接近于零——它的 PHP 文件会被加载、解析,但也就仅此而已,几百微秒的事。而一个在 init 钩子里做三次外部 API 请求、每次都要等 200ms 超时的插件,哪怕你只装它一个,首页也快不了。
所以真实世界里经常出现这种情况:A 站装了 60 个插件,TTFB 400ms;B 站装了 20 个插件,TTFB 1.8 秒。差别不在数量,在于 B 站那 20 个插件里,有几个是重量级的、有几个在每次页面加载时都发起了外部请求、有几个往 wp_options 里塞了几兆的 autoload 数据。
本文拆开讲清楚插件到底在哪些环节消耗性能,以及怎么用几条命令把这些消耗量化出来,最后给出优化优先级。
原理分析:插件影响性能的三个真实通道
通道一:PHP 文件加载与解析。
每次请求,WordPress 会读取 wp_options 中 active_plugins 记录,依次 include 每个插件的主文件。这部分开销是「文件数 × 单文件解析成本」。开启 OPcache 后,解析成本被大幅摊薄,30 个插件和 60 个插件的实际差异通常只有几毫秒。这是《插件越多越慢》这条说法里最不成立的那一半。
通道二:数据库查询与 autoload 数据。
这是真正的大头,而且经常被忽略。WordPress 在启动时会执行 wp_load_alloptions(),把 wp_options 表里所有 autoload = yes 的记录一次性读进内存,每个请求都读一次。很多插件把配置、缓存、甚至整段 HTML 塞进 autoload 选项里,装十个这样的插件,每次请求就要白白拉取几 MB 数据。
-- 查看 autoload 数据的总量与最大的几条
SELECT option_name, LENGTH(option_value) AS bytes
FROM wp_options
WHERE autoload IN ('yes','on','auto-on')
ORDER BY bytes DESC
LIMIT 20;
-- 总量
SELECT SUM(LENGTH(option_value))/1024 AS total_kb, COUNT(*) AS cnt
FROM wp_options
WHERE autoload IN ('yes','on','auto-on');
经验阈值:autoload 数据总量超过 800KB 就要开始查是谁贡献的;超过 2MB 时,TTFB 通常会出现肉眼可见的劣化。
通道三:外部 HTTP 请求。
插件调用 wp_remote_get() 去请求第三方 API(更新检查、字体、统计、授权校验)。这类请求是同步阻塞的,一次 300ms 的外部请求会直接加到 TTFB 上。如果对方服务抖动或超时,你的页面就跟着卡死。
| 性能通道 | 与插件数量的关系 | 典型量级 | 可观测位置 |
|---|---|---|---|
| PHP 文件加载 | 弱相关(有 OPcache 时几乎无关) | 几 ms ~ 十几 ms | Query Monitor Overview |
| 数据库查询 | 中等相关 | 每插件 0–20 条查询 | Query Monitor Queries by Component |
| autoload 数据 | 无关数量,只看总量 | 几十 KB ~ 数 MB | 上述 SQL |
| 外部 HTTP | 无关数量,只看有没有 | 每次 0–1000+ ms | Query Monitor HTTP API Calls |
| 前端 JS/CSS | 中等相关 | 每插件 0–2 个请求 | Query Monitor Scripts & Styles |
结论很清楚:插件数量是一个糟糕的性能代理指标。真正该监控的是三个数字——autoload 总量、每次请求的数据库查询数、每次请求的外部 HTTP 请求数。
保姆级实操
第一步:先量化现状,不要凭感觉
# 1) autoload 数据总量
wp db query "SELECT SUM(LENGTH(option_value))/1024 AS total_kb FROM wp_options WHERE autoload IN ('yes','on','auto-on')"
# 2) 前端真实耗时(跑 3 次取中位数)
for i in 1 2 3; do
curl -s -o /dev/null -w "TTFB=%{time_starttransfer}s 总计=%{time_total}s\n" https://example.com/
done
第二步:定位 autoload 的主要贡献者
SELECT option_name,
LENGTH(option_value)/1024 AS kb,
CASE
WHEN option_name LIKE '%transient%' THEN 'transient(可清)'
WHEN option_name LIKE 'widget_%' THEN '小工具历史数据'
ELSE '插件配置'
END AS kind
FROM wp_options
WHERE autoload IN ('yes','on','auto-on')
ORDER BY kb DESC
LIMIT 15;
看到 transient 类的过期缓存直接清掉;看到某个插件贡献了几百 KB 且无法关闭,就该考虑替换它。
第三步:清理过期 transient
wp transient delete --expired --all
wp db query "DELETE FROM wp_options WHERE option_name LIKE '\_transient\_timeout\_%' AND option_value < UNIX_TIMESTAMP()"
wp db query "DELETE FROM wp_options WHERE option_name LIKE '\_site\_transient\_timeout\_%' AND option_value < UNIX_TIMESTAMP()"
第四步:把不需要的选项改成非 autoload
-- 把某个大选项改为不自动加载
UPDATE wp_options SET autoload = 'no' WHERE option_name = 'some_plugin_big_cache';
注意:如果这个选项在每次请求里都要用到,改成 no 只是把成本从「一次批量读」变成「一次单独查询」,不一定更快。只对「后台才会用到」的选项做这个操作。
第五步:加一个轻量性能日志
在 wp-content/mu-plugins/ 下建一个文件,把每次请求的核心指标写进错误日志,跑一天就能看出波动:
<?php
// mu-plugins/perf-log.php
add_action( 'shutdown', function () {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return;
}
error_log( sprintf(
'[perf] %s | %.3fs | %d queries | %.1fMB',
$_SERVER['REQUEST_URI'] ?? '-',
timer_stop( false, 3 ),
get_num_queries(),
memory_get_peak_usage( true ) / 1048576
) );
} );
timer_stop() 与 get_num_queries() 都是 WordPress 核心函数,前者返回本次请求的执行耗时,后者返回累计数据库查询数。
第六步:按优先级优化
优化顺序固定为:外部 HTTP 请求 → autoload 数据 → 数据库查询 → 插件数量。前三项处理完,你会发现根本不需要删插件。
第七步:清理真正无用的插件
最后才是删。判定标准是三条:功能已不再使用、有更轻的替代、或者它同时属于 识别已弃用插件 中描述的情况。删除前先备份数据库,因为删除会触发 uninstall.php。
常见踩坑
-
为降数量把多个小插件合并成一个大插件:合并后的插件功能更重,往往更慢。
-
装「插件性能监控插件」本身:这类插件自己也会消耗资源,测量完就该停用。
-
忽略 OPcache 的作用:没开 OPcache 时,插件数量的影响会被放大。检查
phpinfo()里的opcache.enable。 -
盲目清空所有 transient:有些 transient 是插件的工作缓存,清掉后第一次访问会更慢。
-
只看首页:后台页面、WooCommerce 的购物车页、搜索页的插件参与度完全不同,要分别测。
-
案例: 某外贸站 42 个插件,站点很慢,站长一直想删插件但不知道删哪个。跑上面的 SQL 后发现 autoload 总量 3.4MB,其中单个
slider_revolution_cache占了 1.9MB,另有 900KB 来自一个统计插件的历史数据。清理并把大选项改为非 autoload 后,autoload 降到 480KB,TTFB 从 1.6s 降到 520ms,一个插件都没删。教训是:先测再动,性能问题几乎从来不是靠删插件解决的。 -
在高峰期做批量清理:删除大量 transient 会造成数据库写压力,选在低峰执行。
总结
记住三条结论:插件数量与性能弱相关;autoload 总量、数据库查询数、外部 HTTP 请求数才是强相关指标;优化顺序永远是前三者优先于删插件。
可以固化的月度检查:查一次 autoload 总量(阈值 800KB)、清一次过期 transient、看一次 TTFF 趋势、复查一次有没有新增的外部请求插件。
如果你想知道怎么把性能开销定位到单个插件身上,Query Monitor 测量插件开销 给出了逐插件量化的方法;而在不动生产站的前提下确认到底是哪个插件在捣乱,则需要 Health Check 排障模式。
