首页 > Wordpress > 正文

WordPress 后台慢?wp_options 膨胀排查

fenij 2026-08-27 32 Wordpress

后台点一下菜单要等两三秒,前台却看着还行——这种「只有登录后才慢」的症状,绝大多数是 wp_options 表里的 autoload 数据涨太大了。这张表有个特性:所有 autoload='yes' 的记录,每加载一个页面都会被整体读出来塞进内存,不管你这个页面用不用得上。数据涨到 1MB 以上,等于每次请求先白拉 1MB 垃圾,加多少缓存插件都救不回来。

先量一下你的 autoload 有多大

别凭感觉。进数据库跑一条 SQL,30 秒出结论:

SELECT SUM(LENGTH(option_value)) AS autoload_bytes,
       COUNT(*) AS autoload_rows
FROM wp_options
WHERE autoload = 'yes';

没装 phpMyAdmin 的用 WP-CLI 更省事:

wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024) AS kb, COUNT(*) AS rows FROM wp_options WHERE autoload='yes';" --allow-root

表前缀不是默认 wp_ 的记得替换。拿到数字后按下面这张表定位自己在什么档:

autoload 体积 状态 该做什么
< 300 KB 健康 别折腾,去查别的原因
300–800 KB 偏大 清 transient,留观
800 KB–1 MB 拖慢明显 逐条排查大记录
> 1 MB 病态 必须动手清理

行数也值得看一眼。健康站点 autoload 一般在 150 到 400 行之间,冲到两三千行说明某个插件在往里面写循环数据。

找出是谁在往里面塞东西

体积超标之后,下一步是揪出最占地方的那几条记录,而不是无脑跑「一键优化」。

SELECT option_name,
       ROUND(LENGTH(option_value)/1024, 1) AS kb
FROM wp_options
WHERE autoload = 'yes'
ORDER BY LENGTH(option_value) DESC
LIMIT 20;

典型输出长这样:

+------------------------------------+-------+
| option_name                        | kb    |
+------------------------------------+-------+
| rewrite_rules                      | 186.4 |
| xyz_slider_cache_all               | 142.7 |
| _elementor_global_css              |  98.2 |
| jetpack_available_modules          |  61.5 |
| wpseo_titles                       |  22.8 |
+------------------------------------+-------+

看到 option_name 里带 cache_transient__log_queue 字样又占几十 KB 的,基本都是插件把临时数据错误地写成了 autoload。rewrite_rules 涨到一两百 KB 通常是自定义文章类型和分类太多,这条不能删,但可以在「设置 → 固定链接」点一次保存让它重建,多余的旧规则会被刷掉。

安全的清理顺序

动手前先备份,这一步不能省:

wp db export backup-before-autoload-$(date +%F).sql --allow-root

接着按风险从低到高来:

1️⃣
清过期 transient
零风险,先做
2️⃣
卸残留插件项
确认插件已删
3️⃣
改 autoload 开关
保留数据,不加载
4️⃣
复测体积
对比清理前后

第一步用 WP-CLI,比手写 SQL 稳:

wp transient delete --expired --allow-root
wp cache flush --allow-root

第三步是很多人不知道的做法。有些数据你不敢删,但它完全没必要每次请求都加载,那就把开关关掉、把数据留着:

UPDATE wp_options
SET autoload = 'no'
WHERE option_name = 'xyz_slider_cache_all';

这比 DELETE 安全得多。改错了大不了改回 'yes',数据一直在那儿。

踩坑实录

有个站 autoload 一直卡在 1.4 MB,清完 transient 只掉到 1.35 MB。排下来最大一条是 _wc_session_expired 之外的 wc_tracker_last_send,才 3 KB,看着都不像凶手。后来把 ORDER BY 换成 COUNT 分组才看明白:SELECT COUNT(*) FROM wp_options WHERE option_name LIKE '\_transient\_timeout\_%' 返回 21400 行。一个已经卸载的抓取插件留下两万多条永不过期的 transient,单条只有几十字节,加起来把表撑爆了。wp transient delete --expired 对它没用,因为这些记录压根没设过期时间。最后是按前缀定向删掉的,删完 autoload 降到 260 KB,后台响应从 2.1 秒回到 0.4 秒。所以别只看单条大小,行数异常同样要查。

清完之后怎么防止复发

清理是一次性的,源头不堵住三个月又会涨回来。三件事值得做:

把 object cache 装上。Redis 或 Memcached 接进来之后,transient 会走缓存而不是数据库,wp_options 直接安静下来。这是最省事的根治手段。

删插件时用后台的「删除」而不是 FTP 删目录。走正常卸载流程会触发 uninstall 钩子清自己的数据,直接删文件夹等于把垃圾永久留在数据库里。

定期抽查。把上面那条 SUM 查询存成一行命令,每月跑一次,超过 500 KB 就查一遍最大记录。

# 加进 crontab,每月 1 号把体积写进日志
0 3 1 * * cd /var/www/html && wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024) FROM wp_options WHERE autoload='yes';" --allow-root >> /var/log/wp-autoload.log

常见问题

问:直接 DELETE 掉那些 cache 类记录会不会出事?
option 名字里明确带 cache、transient 的可以删,插件会重新生成。但设置类的(比如 wpseo_titleselementor_*_settings)删了等于配置清零,这类只能改 autoload 开关,不能删。

问:装个数据库优化插件一键清理,比手动靠谱吗?
清过期 transient 这一块插件做得没问题。但它们不会判断哪条 autoload 该关、哪条该留,遇到我上面那种「两万条无过期时间的僵尸记录」也常常识别不出来。体积超过 1 MB 时还是得自己看一眼 SQL 输出。

问:为什么前台不慢只有后台慢?
前台大概率被页面缓存挡住了,请求根本没进 PHP。后台不能缓存,每次都实打实读一遍 autoload,所以症状先在后台暴露。

把你站点的 autoload 体积和最大那几条 option_name 发到 fenij.com 的评论区,我可以帮你判断哪些能动。

相关完整手册

系统化的排查与配置思路,建议顺手收藏这几篇完整手册: