搜索全站
数据库 8 分钟阅读

WordPress 修订版本与自动保存:清理、限制与关闭方法

一篇文章存了 80 个修订版本,数据库膨胀几百 MB,后台越点越卡。本文讲清修订版本与自动保存的生成机制、wp-config.php 三种控制写法、安全清理历史数据的 SQL 与 WP-CLI 方案,并给出不误删的注意点。

U
UFO_PF 2022-04-20 · 阅读 8 分钟
Wo 数据库
阅读提示
本文约 3,186 字,预计阅读 8 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:数据库莫名涨到 800MB

有个很典型的现象:站点文章才 300 篇,但 wp_posts 表导出后有 700MB,wp_postmeta 更夸张。后台文章列表加载要七八秒。

原因几乎总是同一个:修订版本(revision)。

一篇反复修改的文章,每次点”更新”或每次自动保存,都会往 wp_posts 里插一条 post_type = revision 的记录,同时在 wp_postmeta 里复制一份它当时所有的自定义字段。改 50 次就是 50 条记录 + 几百行 meta。

原理分析:修订版本和自动保存不是一回事

这两个经常被混为一谈,其实机制不同:

项目 修订版本 revision 自动保存 autosave
触发 每次点”更新/发布” 编辑时每隔 60 秒自动触发
存储 每次新建一条记录 浏览器 localStorage + 一条覆盖式记录
post_type revision revision(post_name 带 -autosave-v1)
数量 无限增长 每篇文章只保留 1 条最新的

自动保存的那条记录会覆盖上一次的,不会无限膨胀。真正撑爆数据库的是修订版本。

另外,wp_postmeta 的膨胀比 wp_posts 更严重:某些页面构建器(Elementor、WPBakery)会给每个修订版本存一份完整的布局数据。所以你看到的”数据库大”,八成是 meta 表。

保姆级实操:三步处理

第一步:先看看有多少

SELECT COUNT(*) AS rev_count, SUM(LENGTH(post_content)) AS content_bytes
FROM wp_posts WHERE post_type = 'revision';

或者用 WP-CLI 直接看:

wp post list --post_type=revision --fields=ID,post_parent,post_date --format=count

按文章统计修订数最多的几篇:

SELECT post_parent, COUNT(*) AS cnt
FROM wp_posts
WHERE post_type = 'revision'
GROUP BY post_parent
ORDER BY cnt DESC
LIMIT 20;

第二步:限制未来的产生量(改 wp-config.php)

完全关闭修订(不推荐,因为丢了后悔药):

define( 'WP_POST_REVISIONS', false );

限制每篇最多保留 N 个(推荐):

define( 'WP_POST_REVISIONS', 5 );
define( 'AUTOSAVE_INTERVAL', 120 );   // 自动保存间隔,单位秒

注意:WP_POST_REVISIONS 必须在 /* That's all, stop editing! */ 这一行之前定义,写在文件末尾无效。这是最常见的失误。

只对某些文章类型关闭:

add_filter( 'wp_revisions_to_keep', function( $num, $post ) {
    if ( 'product' === $post->post_type ) {
        return 0;   // 产品不保留修订
    }
    return 5;
}, 10, 2 );

第三步:清理已经产生的历史修订

推荐 WP-CLI,最安全:

# 先看看会删多少(实际不删)
wp post delete $(wp post list --post_type=revision --format=ids) --dry-run

# 确认后执行
wp post delete $(wp post list --post_type=revision --format=ids) --force

数据量太大时命令行参数会超长,用循环:

wp post list --post_type=revision --format=ids --posts_per_page=500 > /tmp/ids.txt
while read -r ids; do
  [ -z "$ids" ] && continue
  wp post delete $ids --force --quiet
done < /tmp/ids.txt

纯 SQL 版本(更快,但务必先备份):

-- 先备份
-- wp db export before-revision-clean.sql

DELETE p, pm
FROM wp_posts p
LEFT JOIN wp_postmeta pm ON pm.post_id = p.ID
WHERE p.post_type = 'revision';

这条语句用 DELETE p, pm 的多表删除语法,一次性清掉修订记录和它关联的 meta。只删 wp_posts 不删 meta 的话,wp_postmeta 会留下大量孤儿行,等于白清理一半。

清理后优化表释放空间:

OPTIMIZE TABLE wp_posts;
OPTIMIZE TABLE wp_postmeta;

InnoDB 的 OPTIMIZE TABLE 会重建表并锁表,大表执行时间可能几分钟,一定要在业务低峰做,且确保磁盘剩余空间大于表大小。开启 innodb_file_per_table(MySQL 5.6+ 默认开启)才会真正把空间还给文件系统。

常见踩坑与失败案例

  1. define 写错位置:写在 wp-config.php 末尾、require_once(ABSPATH . 'wp-settings.php') 之后,常量不生效,白改。
  2. 案例:某站在 functions.php 里用 remove_post_type_support( 'post', 'revisions' ) 想关闭修订——这个只对新建文章类型有效,对已有的 post 无效,因为他是在 init 之后才执行的。正确方式是 wp-config.php 定义常量,或用 wp_revisions_to_keep 过滤器。
  3. 误删 autosave 导致正在编辑的内容丢失:清理时如果有编辑正在写文章,他的 autosave 被删,浏览器恢复提示会失效。深夜清理最稳妥。
  4. 用了修订版本做协作审核:有些团队靠 revision 追溯谁改了什么,一刀切关掉会丢能力。这种情况建议设成 10~20 而不是 false。
  5. WooCommerce / 自定义文章类型:WP_POST_REVISIONS 对所有支持 revision 的类型生效,产品、页面也一样。如果只针对文章,用过滤器判断 post_type。
  6. 清理后后台还是慢:那问题不在修订,去查 wp_options 里的 _transient_ 垃圾和插件自己建的表(如 wp_wfHits、wp_social 统计表)。

总结

处理修订版本的顺序是:先量化 → 再用 wp-config.php 里 WP_POST_REVISIONS 常量限制增量(写在正确位置)→ 最后用 WP-CLI 或双表 DELETE 清存量 → OPTIMIZE TABLE 在低峰期释放空间。日常建议保留 5~10 个修订,既留了后悔药,又不至于让数据库失控。如果站点是 Elementor 之类构建器做的,效果会特别明显,往往一清理就是几百 MB。

U
UFO_PF作者

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

留下你的想法

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