WordPress wp_options 表膨胀排查:自动加载项与修订版本清理实操

站点跑了两年,前台打开变慢、后台发布文章一直转圈,可主机面板里 CPU 和内存都不高——这类问题常常不在[服务器配置](https://cn.hostease.com/blog/server/),而在数据库。WordPress 的 wp_options 表会随着插件安装、主题切换、缓存插件残留不停堆叠,其中被标记为自动加载(autoload)的选项,会在每一次页面请求里被整体读进内存;文章修订版本则在 wp_posts 里悄悄累积。这篇指南教你用几条 SQL 和 WP-CLI 命令定位这两处膨胀,完成一次可回滚的清理,并把增长重新关回可控范围。

wp_options 自动加载项与修订版本膨胀概念配图

wp_options 膨胀的两个真实来源

WordPress 在每次请求开始时,会执行一次取回全部自动加载选项的查询,把结果放进 alloptions 缓存。这批数据是”每页都要付”的固定成本:首页、文章页、后台页面、AJAX 请求都绕不开它。表里多出 500KB 自动加载数据,意味着每天几万次请求都要多读这 500KB,而它换来的是一个访客根本看不到的中间结果。

增长通常来自两类东西。一类是插件和主题的残留:插件卸载了,option 还留在表里;页面构建器、SEO 插件、表单插件习惯把整份配置和缓存写成一个巨大的数组塞进单个 option。另一类是本来不该自动加载的东西被写成了自动加载,比如定时任务数组、rewrite 规则、第三方统计脚本配置。

WordPress 6.6 之后,wp_options.autoload 列的取值从 yes/no 改成 on/off,并对新写入的大体积选项引入 auto-on/auto-off,由核心按体积判断是否随请求加载。这意味着统计自动加载数据时只查 autoload='yes' 会漏掉一半,必须同时覆盖 yes、on、auto-on。很多站点”清理完没感觉”,第一步就错在这里。

先测量:三组数字决定要不要动手

清理之前先把账算清楚,否则删完也说不清有没有收益。先看表体积,再按体积排序看自动加载项,最后数修订版本,这三组数字就是后面验证效果的基准。

wp db size --tables --human-readable

wp db query "SELECT option_name, LENGTH(option_value) AS bytes
FROM wp_options WHERE autoload IN ('yes','on','auto-on')
ORDER BY bytes DESC LIMIT 20;"

wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024) AS autoload_kb
FROM wp_options WHERE autoload IN ('yes','on','auto-on');"

wp post list --post_type=revision --format=count

判断标准可以简单一些:自动加载总量控制在 800KB 以内算健康,超过 1MB 时首字节时间(TTFB)通常能看出差别;单个选项超过 100KB 基本可以确定是插件写的缓存数组。修订版本没有绝对上限,但超过两万条时,备份体积和导出时间会明显变长。如果这一步发现自动加载数据不大、查询却很慢,那方向就错了,先去看慢日志里具体是哪条 SQL,我们另有一篇讲索引与冗余数据处理的排查方法:WordPress 查询慢的数据库处理。

自动加载选项在每次请求中的读取路径

把自动加载大户摘下来

顺序上先处理”确定是垃圾”的,再处理”还要用但不能常驻”的,最后才考虑删除。每一步都能单独回退,不需要一次做完。

  • 过期 transient:跑一次 wp transient delete --expired;如果长期堆积外部 API 结果,再执行 wp transient delete --all。transient 存在 wp_options 里,过期不会自动消失。
  • 插件残留 option:用 wp option list --search='*前缀*' --fields=option_name,size_bytes 找出,确认插件已卸载后再 wp option delete <option_name>。
  • 要保留但不该常驻的大选项:wp option update <key> "$(wp option get <key> --format=json)" --format=json --autoload=no,值不变,只把自动加载关掉。
  • rewrite 规则重复写入时,用 wp rewrite flush --hard 重建一次,避免同一份规则在表里留多份。

做完这四件事,回到第一步的求和 SQL 复测。多数站点会掉 30%-60%,如果几乎没变化,说明真正的大户是某个还在工作的插件缓存项,它需要单独判断:把 autoload 关掉可能让插件每次都重新计算,反而更慢,这种情况更适合先确认它写入的频率。

修订版本与自动保存留下的体积

每按一次保存,WordPress 可能生成一条修订记录;编辑器的自动保存也会留下痕迹。修订版本的价值是回滚,代价是 wp_posts 和 wp_postmeta 体积上涨:备份变大,导出迁移更慢,后台文章列表和统计查询要扫描的范围也被拉长。它不会让前台查询直接变慢,但会让整库的维护成本一年比一年高。

先看规模,再定策略。wp post list --post_type=revision --format=count 给出的数字如果到了四位数甚至五位数,就该收口了。把上限固定下来:wp config set WP_POST_REVISIONS 5 --raw,--raw 保证写入的是整数而不是字符串;完全不保留可以用 false,但正常内容站建议留 5-10 条,出问题时仍有回滚余地。

清理历史修订必须分批执行,一次传入上万个 ID 很容易撞上命令行长度限制或 PHP 内存上限。先取一批 ID,再按批删除:

IDS=$(wp post list --post_type=revision --format=ids --posts_per_page=500)
wp post delete $IDS --force

删除不可撤销,所以先备份三张核心表:mysqldump -u用户 -p 数据库名 wp_options wp_posts wp_postmeta > backup.sql。备份策略上别只留一份当天的全量,全量与增量怎么搭配,可以参照WordPress 备份策略指南里的分层做法。

修订版本堆积前后的数据量与表体积对比

回收空间并验证效果

删掉行不等于文件变小。InnoDB 删除记录后只是把空间标记为可复用,表文件不会自动收缩,需要一次重建:wp db optimize,底层执行的是 OPTIMIZE TABLE。这一步会重建整张表、需要接近表体积的额外磁盘空间,并且可能持有表锁,务必安排在低峰时段;大表更稳妥的做法是先 wp db repair 确认结构完好,再重建。完整的修复与优化流程,可以对照WordPress 数据库修复与优化实操。

验证时回到开头那三组数字:自动加载总量、wp_options 表体积、修订条数。再补两个体验指标:后台文章列表打开时间、前台首页 TTFB。如果数字都降了页面却没变快,说明瓶颈不在数据库,转去看 PHP-FPM 进程数与对象缓存命中率,那属于另一条优化路径。

稳态运维:让表不要长回去

清理是一次性的,防增长是长期动作。下面几件事放进月度巡检,wp_options 就不会再失控。

  • 每月记录一次自动加载总量和修订条数,写进同一张巡检表;超过 1MB 或修订超过两万条就安排处理。
  • 每周跑 wp transient delete --expired,外部 API 类缓存过期后最容易无声堆积。
  • 安装新插件前先确认它写什么自动加载选项,页面构建器、统计埋点、A/B 测试插件是重点排查对象。
  • 用 Redis 对象缓存把重复查询挡在数据库前面,参考WordPress 对象缓存接入实战;它减少查询次数,但不减小 alloptions 的体积,两件事要分开做。
  • 迁移或例行备份前先清一次过期 transient 与老修订,备份体积和恢复时间都会下降。

清理四个阶段的顺序示意

四个容易踩的坑

  • 直接 DELETE FROM wp_options 有风险:很多选项存的是序列化数组,插件下次读取会拿到空值或直接报错,用 wp option delete 让它走正常钩子。
  • 把 WP_POST_REVISIONS 设成 0 之前,先确认团队不需要回滚:清空后只能靠数据库备份恢复。
  • OPTIMIZE TABLE 不是越频繁越好,表体积不到几十 MB 时收益有限,反而多一次锁表风险。
  • 只统计 autoload='yes' 会漏掉 6.6 之后的 on 与 auto-on,口径不对,清理就变成盲猜。

如果你用的是带 cPanel 的[共享主机](https://cn.hostease.com/shared-hosting.html)(共享主机:多个站点共用一台服务器的资源),数据库操作前先在面板里做一次整库备份,再执行 OPTIMIZE;这类环境通常没有 root 权限,改 my.cnf 的参数要先问主机商。在 Hostease 的[虚拟主机](https://cn.hostease.com/shared-hosting.html)上,备份和还原都能在面板里完成,清理步骤与上面完全一致,只是把命令行换成 phpMyAdmin 的对应操作。

总结:一次清理,三件事收口

wp_options 膨胀和修订版本堆积都不是故障,而是长期运行的自然结果,共同特征是”看不见但每次请求都在付费”。建议按测量、摘除自动加载、限制并清理修订、回收空间验证四步走,每一步都留一份可回滚的备份;如果你需要长期稳定,把自动加载总量和修订条数做成月度指标,比每次卡了再救火有效得多。清理完成后一周再复测一次,确认数字没有反弹,也能顺手验证备份是否真的可用。

发表评论