搜索全站
插件 10 分钟阅读

Advanced Database Cleaner 清理冗余数据:清理项选择与定时任务

数据库越跑越臃肿?本文讲清修订版本、过期 transient、孤立元数据等冗余数据的成因,给出清理顺序、可执行的 SQL 与 WP-CLI 命令,以及定时清理的安全做法。

U
UFO_PF 2024-02-08 · 阅读 10 分钟
Ad 插件
阅读提示
本文约 3,666 字,预计阅读 10 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:数据库从 80MB 涨到 900MB,站点却没多几篇文章

站点跑了两三年,数据库体积涨了十倍,文章数才多了两百篇。打开 phpMyAdmin 一看,wp_posts 里躺着几万条 revision 和 auto-draft,wp_options 里塞满了过期的 _transient_timeout_,还有一批早已卸载的插件留下的孤儿表。这些冗余数据不会让站点立刻报错,但会持续拖慢三件事:备份耗时、后台列表加载、以及数据库本身的查询效率。

Advanced Database Cleaner 这类插件的价值,就是把这些「看不见的垃圾」可视化:它能列出各类可清理项、给出数量估计,并支持按计划执行。但清理本身是有风险的——删错了表、删掉了正在使用的元数据,站点会立刻出问题。所以关键不在于「敢不敢点清理」,而在于知道每一项是什么、能不能删、删之前怎么兜底。

原理分析:冗余数据从哪来

冗余类型 成因 风险等级
修订版本 / 自动草稿 每次保存文章生成一条 revision 低,可放心删
回收站中的文章与评论 删除后进入回收站,默认保留 30 天 低
过期 transient 插件写入的临时缓存,带超时时间 低,只删过期的
孤立 postmeta 文章被删后 meta 未清理 中,需确认对应关系
孤立 term relationship 分类关联指向不存在的文章 中
孤儿数据表 卸载插件未清理表 中,需确认插件已不用
已失效的计划任务 插件卸载后 cron 事件残留 低

最需要谨慎的是「孤立」类数据:它们的判定依赖文章是否还存在,如果判定逻辑与插件不一致(比如站点用了自定义文章类型或分表),可能误删仍在使用的元数据。先备份、再小批量、最后核对,是唯一稳妥的顺序。

还有一类容易被忽略的:插件卸载后残留的计划任务。它们不会占多少空间,但每次 WP-Cron 触发时都会执行失败回调,产生日志噪音。这类问题用 WP-CLI 查看最直观。

保姆级实操:按风险从低到高清理

步骤1:先完整备份数据库。 这一步不能省,且要确认备份文件可下载、可导入。

wp db export /tmp/db-before-cleanup.sql
ls -lh /tmp/db-before-cleanup.sql

步骤2:摸清各类冗余的数量。 先看数量,再决定清不清。数量小的项目不必折腾。

-- 各类数据的数量统计
SELECT post_type, COUNT(*) AS cnt
FROM wp_posts
GROUP BY post_type
ORDER BY cnt DESC;

-- 过期 transient 的数量
SELECT COUNT(*) AS expired_transients
FROM wp_options
WHERE option_name LIKE '_transient_timeout_%'
  AND option_value < UNIX_TIMESTAMP();

步骤3:清理修订版本与自动草稿。 风险最低,收益通常最大。用 WP-CLI 比在后台点更可控。

# 删除所有修订版本(数量大时分批执行)
wp post delete $(wp post list --post_type=revision --format=ids --posts_per_page=1000) --force
# 清空回收站
wp post delete $(wp post list --post_status=trash --format=ids) --force

步骤4:清理过期 transient。 只删已过期的,不要动未过期的,否则正在使用的缓存会被清掉。

-- 只删除已过期的 transient(先 SELECT 确认数量,再 DELETE)
DELETE FROM wp_options
WHERE option_name LIKE '_transient_timeout_%'
  AND option_value < UNIX_TIMESTAMP();

DELETE FROM wp_options
WHERE option_name LIKE '_transient_%'
  AND option_name NOT LIKE '_transient_timeout_%'
  AND option_value = '';
# WP-CLI 等价做法
wp transient delete --expired

步骤5:处理孤立 postmeta。 这一项要先看清楚数量与样例,确认不是自定义文章类型在使用的元数据,再交给插件或 SQL 处理。

-- 查看孤立 postmeta 的数量(post 已不存在)
SELECT COUNT(*) AS orphan_meta
FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL;

步骤6:检查残留的计划任务与孤儿表。 用 WP-CLI 看计划任务,用 SQL 看可疑的表名。

# 列出所有计划任务,找出插件卸载后残留的钩子
wp cron event list
wp cron event delete 已失效的钩子名

步骤7:配置定时清理。 用系统计划任务而不是 WP-Cron,避免受访问触发的不确定性影响;频率按月即可,不必每天跑。

# 每月 1 号凌晨 3:30 清理过期 transient 与修订版本
30 3 1 * * /usr/local/bin/wp --path=/var/www/site/public_html transient delete --expired > /dev/null 2>&1
40 3 1 * * /usr/local/bin/wp --path=/var/www/site/public_html post delete \
  $(wp post list --post_type=revision --format=ids --posts_per_page=2000) --force > /dev/null 2>&1

步骤8:核对清理效果。 清理后对比表体积,并抽查前台页面与后台列表是否正常。

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
LIMIT 10;

常见踩坑

  1. 没备份就点「全部清理」。插件的批量按钮不会替你做判断,一旦删错不可逆。
  2. 删掉了未过期的 transient。把 _transient_* 全清,导致购物车、登录态、接口缓存被清空。
  3. 误删孤立 postmeta。站点用了自定义文章类型或外部表时,判定可能出错。先看数量与样例再动手。
  4. 清理孤儿表后插件无法重装。删了表但插件目录还在,重新启用时会因为缺表而报错。确认插件确实不再使用。
  5. 大表 DELETE 锁表导致站点卡顿。wp_options 上百万行时,一条 DELETE 可能锁表几十秒。分批删除或放在低峰执行。
  6. 案例:某站点在活动高峰期用插件执行「清理所有 transient」,导致购物车会话全部失效,正在下单的用户被清空购物车,当天转化率掉了一半。整改后改为:只清理过期项、放在凌晨执行、并在活动期间禁用该计划任务。
  7. 清理后没有核对前台。数据库体积确实降了,但某个页面因为缺少 meta 而显示异常。清理后必须抽查关键页面。
  8. 把修订版本限制忘了配。清理完又会涨回来。可以结合 WP_POST_REVISIONS 常量做长期控制,这与WP Crontrol 管理定时任务(Cron)里讲的「用计划任务做长期治理」是同一个思路。

总结

清理顺序应该是:备份 → 统计数量 → 清理修订版本与回收站 → 清理过期 transient → 谨慎处理孤立数据 → 检查残留计划任务与孤儿表 → 配置按月定时清理 → 抽查前台。判断该不该删的标准是:修订版本、自动草稿、已过期 transient 可以放心删;任何「孤立」类数据都要先看样例再决定。Advanced Database Cleaner 的作用是把这些项目可视化并支持定时执行,但它不能替你承担判断责任。另外,清理只是治标,长期控制修订版本数量、卸载插件时清理残留,才是治本。数据库里表单条目的留存策略,可参考表单数据存储与导出(GDPR 考量)。

U
UFO_PF作者

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

留下你的想法

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