搜索全站
性能优化 13 分钟阅读

WordPress 后台卡顿怎么排查:wp-admin 慢的六个根因与优化

前台很快但后台点一下卡三秒,多半不是服务器问题。本文给出后台卡顿的六个真实根因(心跳 API、admin-ajax、对象缓存缺失、慢插件、数据库膨胀、外部请求),并附 Query Monitor 定位方法和逐项优化代码。

U
UFO_PF 2023-09-17 · 阅读 13 分钟
Wo 性能优化
阅读提示
本文约 5,104 字,预计阅读 13 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:前台 1 秒,后台 5 秒

这是个很典型的症状:用 PageSpeed 测前台首页 1.2 秒,但后台点”所有文章”要等五秒,编辑文章点”更新”要转半天。

原因很简单:前台有整页缓存,后台没有。后台每个请求都是实打实的 PHP 执行 + 数据库查询 + 外部 HTTP 请求,所有被缓存掩盖的问题在后台全部暴露出来。

所以后台慢,其实是站点”真实性能”的体检报告,值得认真排查。

原理分析:后台请求的六个耗时来源

一次后台请求的成本大致分六块:

  1. WordPress 核心加载:读 wp_options 的 alloptions、加载激活插件、执行 init 钩子;
  2. 数据库查询:文章列表要查 wp_posts + wp_postmeta(每行 meta 一次查询,未缓存时很恐怖);
  3. 心跳 API(Heartbeat):后台每 15~60 秒自动 POST 到 admin-ajax.php,做 autosave、锁检测、通知轮询;
  4. 插件的外部 HTTP 请求:更新检查、License 验证、统计上报,同步阻塞;
  5. 对象缓存缺失:没有 Redis/Memcached 时,同一次请求里的重复查询无法复用;
  6. PHP 执行:慢插件、低效正则、大循环。

其中 3、4 两项是最容易被忽略、也最容易见效的。

保姆级实操

第一步:量化定位(装 Query Monitor)

装插件 Query Monitor,后台顶栏会出现一组统计:页面生成时间、数据库查询数、查询耗时、最慢的查询、HTTP 请求、钩子耗时、PHP 错误。

重点看三个数字:

  • Peak memory usage:正常后台页 40~80MB,超过 128MB 说明有插件吃内存;
  • Database queries:文章列表页正常 100~300 次,超过 800 次就有问题;
  • HTTP API Calls:这一项一展开,经常能看到七八个外部请求,每个 300ms+。

Query Monitor 的 “Queries by Component” 面板能直接告诉你是哪个插件贡献了最多查询,这是最省事的定位方式。

第二步:干掉心跳 API 的开销

心跳 API 在编辑文章时每 15 秒发一次请求,做自动保存;在仪表盘每 60 秒发一次。多人同时写文章时,它会持续占着 PHP-FPM 进程。

装插件 “Heartbeat Control” 可以可视化配置。代码方式:

// 只在文章编辑页保留心跳,其他地方禁用
add_action( 'init', function() {
    if ( ! is_admin() ) return;

    $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
    $keep   = $screen && in_array( $screen->id, array( 'post', 'page' ), true );

    if ( ! $keep ) {
        wp_deregister_script( 'heartbeat' );
    }
}, 1 );

// 把心跳频率从 15 秒改成 60 秒
add_filter( 'heartbeat_settings', function( $settings ) {
    $settings['interval'] = 60;
    return $settings;
} );

这一项通常能让后台的持续 CPU 占用下降 30% 以上,尤其是开了多个后台标签页的情况。

第三步:屏蔽插件的外部 HTTP 请求

很多商业插件每次后台加载都会去验证 License、检查更新。如果对方服务器在国外,一次请求 500ms~2s,同步阻塞,后台直接卡。

在 Query Monitor 的 HTTP 面板里能看到具体 URL。屏蔽方式:

// 屏蔽指定的外部请求
add_filter( 'pre_http_request', function( $preempt, $parsed_args, $url ) {
    $blocked = array(
        'api.example-license.com',
        'stats.some-plugin.com',
        'www.gravatar.com',
    );
    foreach ( $blocked as $host ) {
        if ( false !== strpos( $url, $host ) ) {
            return new WP_Error( 'http_request_blocked', 'Blocked for performance' );
        }
    }
    return $preempt;
}, 10, 3 );

更精细的做法——只缩短超时,不完全屏蔽:

add_filter( 'http_request_timeout', function( $timeout ) {
    return 3;   // 默认 5 秒,改 3 秒
} );
add_filter( 'http_request_args', function( $args, $url ) {
    $args['timeout'] = 3;
    return $args;
}, 10, 2 );

别屏蔽更新检查(api.wordpress.org),否则收不到安全更新。

第四步:上对象缓存

后台每个请求会重复查 wp_options 和 meta。装 Redis 对象缓存能把大量重复查询变成内存读取。

# 装 Redis 服务端
sudo apt install -y redis-server php8.2-redis

# 装插件
wp plugin install redis-cache --activate
wp redis enable
wp redis status

效果:后台文章列表的数据库查询数通常能降 40%~60%。

第五步:清理数据库膨胀

后台慢很大一部分原因是 wp_posts / wp_postmeta / wp_options 太大。

-- 看各表大小
SELECT table_name,
       ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY size_mb DESC;

重点清理三项(都要先备份):

# 修订版本
wp post delete $(wp post list --post_type=revision --format=ids) --force

# 过期 transient
wp transient delete --expired
wp transient delete --all    # 更彻底,但会清掉插件缓存

# 孤儿 meta(没有对应文章的 meta 行)
DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL;

wp_options 里的 transient 堆积是最常见的”隐形杀手”:

SELECT COUNT(*) FROM wp_options WHERE option_name LIKE '%_transient_%';

几万行的话,后台每次加载都要扫一遍。清理:

DELETE FROM wp_options WHERE option_name LIKE '_transient_timeout_%' AND option_value < UNIX_TIMESTAMP();
DELETE FROM wp_options WHERE option_name LIKE '_site_transient_timeout_%' AND option_value < UNIX_TIMESTAMP();

第六步:禁用不必要的后台功能

// 关掉仪表盘的小工具(减少外部请求,比如 WordPress 新闻)
add_action( 'wp_dashboard_setup', function() {
    remove_meta_box( 'dashboard_primary', 'dashboard', 'side' );   // WordPress 活动与新闻
    remove_meta_box( 'dashboard_quick_press', 'dashboard', 'side' );
    remove_meta_box( 'dashboard_activity', 'dashboard', 'normal' );
} );

// 减少文章列表每页条数(默认 20,改成 10 能显著加快)
add_filter( 'edit_posts_per_page', function() { return 10; } );

第七步:服务器层面

  • PHP-FPM 进程数不足:后台并发请求多时排队。检查 pm.max_children,1GB 内存的机器建议 10~20;
  • OPcache 没开:PHP 8 必须开 OPcache,否则每个请求都重新编译:

ini
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=2

  • MySQL 慢查询:开慢查询日志看:

sql
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;

常见踩坑与失败案例

  1. 案例一:后台卡到 8 秒,装了 Query Monitor 发现是某个”SEO 分析”插件每次加载都去请求自己的 API(在美国),超时 5 秒。屏蔽后降到 1.1 秒。
  2. 案例二:某站后台文章列表 3000+ 查询,根因是一个插件给每篇文章都查了 5 个 meta,且没用 update_post_meta_cache。改成批量查询后降到 200。
  3. 盲目删 transient 导致 WooCommerce 数据异常:wp_options 里的 transient 有些是业务数据(如运费缓存)。清理前先确认,不要在生产高峰期做。
  4. Redis 装了但没生效:wp redis status 显示 “Not enabled”,通常是 PHP 没装 redis 扩展或 Redis 服务没启动。
  5. 屏蔽 api.wordpress.org 后收不到安全更新:只屏蔽第三方插件的域名,核心更新检查必须放行。
  6. 心跳完全禁用导致 autosave 失效:编辑文章时如果禁用心跳,自动保存不工作,关掉浏览器就丢内容。只在非编辑页禁用。
  7. Windows/低配 VPS 上的 OPTIMIZE TABLE:会锁表,大表执行时后台全部卡死。务必在低峰期做。

总结

后台卡顿排查的标准流程是:装 Query Monitor 看三项指标(查询数、内存、HTTP 请求)→ 按”Queries by Component”定位插件 → 依次处理心跳 API、外部 HTTP 请求、对象缓存、数据库膨胀 → 最后检查 PHP-FPM 进程数和 OPcache。其中见效最快的三项是:禁用心跳(非编辑页)、屏蔽第三方插件的 License/统计请求、装 Redis 对象缓存。后台慢本质上是站点真实性能的体检报告,把它修好了,前台的稳定性也会跟着提升。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。