数据库优化与冗余清理
先看 wp_options,再看修订版本
两百个页面的企业站,数据库导出却有 300MB,后台每点一下等三秒——九成不是主机性能不够,而是数据库里堆了几年没人清的垃圾。这一页讲清冗余从哪来、怎么用 SQL 量出来、哪些能直接删、哪些删了会出事。
数据库是怎么胖起来的
六种垃圾,五种没人管
WordPress 的设计偏保守:几乎不主动删数据。文章改十次留十个版本,删掉的插件留下的选项永远躺在表里,连回收站里的东西都默认保留三十天。这种”什么都不丢”的策略在内容站是优点,在企业站就是负担。
修订版本 post revisions
每次点”保存草稿”或自动保存都会写一条 post_type='revision' 的记录,同时往 wp_postmeta 写一份字段。一篇反复修改的产品页留下几十个版本很常见,占用的体积往往是正文的十倍以上。这是企业站最肥的一块。
- 默认数量不限,WordPress 会一直存
- 删除修订不影响已发布内容
自动草稿与回收站
post_status='auto-draft' 是编辑器打开就生成、从没保存过的空记录,一个站几百条很平常。回收站内容默认保留 30 天,长期不管就是几百条待删记录占着表。
孤立元数据 orphaned meta
文章或用户被删掉后,wp_postmeta、wp_usermeta、wp_term_relationships 里对应的记录不一定跟着删。装了又删的插件尤其容易留下大批无主 meta,查询时全表扫描。
过期 transient
wp_options 里 _transient_ 与 _transient_timeout_ 成对出现。SEO 插件、汇率、天气、社交计数都会写。正常会自己过期,但插件停用后没人来清,几千条过期记录就那么留着,还会被 autoload 一起加载。
垃圾评论与 pingback
没装防垃圾评论的站,wp_comments 里几万条 spam 是常态,每条还带 meta。这类表膨胀会直接拖慢后台评论页与前台评论查询。外贸站尤其明显,因为暴露在公网且常年有爬虫扫表单。
wp_options 的 autoload 堆积
这是最容易被低估的一项。autoload 的选项会在每次请求时被一次性读进内存,theme_mods、构建器的全局设置、插件的 license 缓存全在里面。几百 KB 乘以每天的请求数,就是实打实的损耗。
动手之前先量一遍
四条 SQL 看清家底
清理最忌讳凭感觉删。下面几条查询在 phpMyAdmin 或 Adminer 里直接跑,只读不写,跑完你就知道该从哪下手。执行前请先确认表前缀,示例里用的是默认的 wp_。
哪张表最占地方
查 information_schema.tables,按数据加索引的总体积倒序排,取前十五张。正常的站 wp_posts 与 wp_postmeta 应该排在前两位,如果 wp_options 挤进前三,说明 autoload 或 transient 出了问题。
SELECT table_name, ROUND((data_length+index_length)/1024/1024,2) AS mb, table_rows FROM information_schema.tables WHERE table_schema=DATABASE() ORDER BY mb DESC LIMIT 15;
- 字段用 data_length 加 index_length 求和
- table_rows 是估算值,会有偏差,看趋势不看绝对值
autoload 到底多大
对 wp_options 中 autoload='yes' 的行求 LENGTH(option_value) 之和。经验值是 300KB 以内算健康,超过 800KB 就该排查,超过 2MB 会明显拖慢每一次请求。再按长度倒序列出前二十条,通常一眼就能看出是哪个插件写的。
SELECT ROUND(SUM(LENGTH(option_value))/1024,1) AS autoload_kb FROM wp_options WHERE autoload='yes';
修订版本有多少
统计 post_type='revision' 的记录数,再和正式文章数对比。比例超过 10:1 就属于异常。同时统计 auto-draft 与 trash 的数量,这三类可以放在一起看。
SELECT post_type, post_status, COUNT(*) FROM wp_posts GROUP BY post_type, post_status ORDER BY 3 DESC;
- 修订记录本身不含附件,删了不会掉图
- 但删之前务必确认没有插件依赖修订做版本对比
孤儿数据有多少
用子查询比对 wp_postmeta.post_id 与 wp_posts.ID,能查出没有归属的 meta 条数。同理查 wp_term_relationships 里指向已删文章的记录。这两类数据不占最大体积,但会让 JOIN 变慢。
SELECT COUNT(*) FROM wp_postmeta pm LEFT JOIN wp_posts p ON p.ID=pm.post_id WHERE p.ID IS NULL;
清理前把结果截图存档。前后各存一份,能直观看出效果,出问题时也能快速判断是不是清理引起的。
分四步清理
从最安全的开始
顺序很重要:先停掉产生垃圾的源头,再删存量,最后整理表空间。反过来做,删完第二天又长回来。
先设上限,止住增量
在 wp-config.php 里加 define('WP_POST_REVISIONS', 5); 限制每篇最多留五个版本,加 define('EMPTY_TRASH_DAYS', 7); 把回收站保留期缩到 7 天。这两行写进去,增量就被控住了。
删修订、草稿、回收站
SQL 层面先删 meta 再删主表:DELETE pm FROM wp_postmeta pm JOIN wp_posts p ON p.ID=pm.post_id WHERE p.post_type='revision';,之后才执行 DELETE FROM wp_posts WHERE post_type='revision';。顺序反了会留下大批孤儿 meta。用 WP-CLI 更稳:wp post delete $(wp post list --post_type=revision --format=ids) --force,它会连带清理关联数据。
清 transient 与孤儿 meta
删 option_name LIKE '_transient_%' 与 '_transient_timeout_%' 的记录,注意别误删 _site_transient_ 里的必要项。语句形如 DELETE FROM wp_options WHERE option_name LIKE '_transient_%';,下划线要转义,否则会连带匹配到别的名字。孤儿 meta 用 NOT IN 子查询删除,一次别超过五千条,分批跑避免锁表。
重建表空间
DELETE 只是把行标记为可复用,文件不会变小。执行 OPTIMIZE TABLE wp_posts, wp_postmeta, wp_options; 才会真正回收。InnoDB 需要 innodb_file_per_table=ON 才能把空间还给磁盘,共享表空间下只能整理碎片。
卡在”Table is marked as crashed and should be repaired”的,先 REPAIR TABLE 再谈优化。出现 MySQL server has gone away,多半是单条语句影响行数太多,加 LIMIT 分批处理。完整处理路径见WordPress 数据库报错处理。
wp_options 专项
表不大,伤害最大
这张表通常只有几 MB,却是全站最热的一张表——每个请求都要读它。它的膨胀不会让数据库变大,只会让每个页面慢几十到几百毫秒。
先分清哪三类选项
一是核心必需项(siteurl、home、active_plugins、rewrite_rules),绝对不能碰;二是插件配置项,量小但值大;三是临时缓存项,包括 transient、rss_ 开头的订阅缓存、_wc_session_ 之类的会话数据。要清理的只有第三类。
rewrite_rules 可能非常大
装了多语言、商城、多分类的站,这一条 option 能到几百 KB,而且它是 autoload 的。它不能删,但要确认没被写坏。发现几条同名 option 反复出现,说明有插件每次请求都写库,属于代码问题。
把不必要的东西踢出 autoload
插件停用后,它留下的 option 往往还是 autoload=’yes’。可以执行更新语句把这些没人读的项改成 autoload='no',改动可逆、风险低。改完刷新一次前台,再量一遍 autoload 体积,通常能看到明显下降。
别用”一键优化”插件全选
WP-Optimize、Sweeper 这类工具很方便,但默认勾选里可能有”删除所有 transient”或”清理未使用的表”。前者让缓存瞬间失效、流量全打到数据库,后者可能删掉别的程序共用的表。执行前逐项看清。
一个实用的习惯:每次停用或卸载插件后,立刻跑一次 autoload 体积查询。装了删、删了装是常态,留下几百条垃圾选项自己不会消失。这条习惯坚持一年,能省掉一次”网站莫名其妙变慢”的排查。
七类冗余逐项对照
能删什么,代价是什么
“保留建议”一列是我们给客户的默认配置,可按站点实际情况调整。
| 冗余类型 | 所在表 | 典型占比 | 处理方式 | 风险 |
|---|---|---|---|---|
| 文章修订 | wp_posts / wp_postmeta | 30%-60% | 保留最近 5 个,其余删除 | 低,失去历史版本对比 |
| 自动草稿 | wp_posts | 5%-15% | 全部删除 | 极低 |
| 回收站内容 | wp_posts | 5%-10% | 保留 7 天后清理 | 低,误删无法找回 |
| 过期 transient | wp_options | 10%-25% | 按前缀删除 | 中,缓存需重新生成 |
| 垃圾评论 | wp_comments | 视站而定 | 标记 spam 后批量删 | 低,注意别误删真实询盘 |
| 孤儿 meta | wp_postmeta / wp_usermeta | 5%-20% | NOT IN 子查询分批删 | 中,子查询写错会误删 |
| 表碎片 | 全部 InnoDB 表 | 10%-30% | OPTIMIZE TABLE | 中,执行期间锁表 |
体积下降通常在三到六成,具体取决于站点历史。真正影响前台速度的往往不是体积,而是查询次数与 autoload 大小,清理之后要配合缓存层看效果。做法见WordPress 速度优化。
数据库清理常见五问
不会。修订是独立记录,文章的当前内容存在另一条记录里。删掉只失去”回看历史版本”的能力,不影响前台。例外是有插件把数据只存在修订里,少见但存在,所以第一次清理前一定要有可用的数据库备份。
DELETE 只是把行标记为可复用,InnoDB 文件不会自动收缩。要让磁盘空间真正释放,需要 OPTIMIZE TABLE 重建表,并确认 innodb_file_per_table 已开启。即使不重建,释放的空间也会被后续插入复用,性能改善往往在 OPTIMIZE 之前就出现了。
工具没问题,问题在默认勾选。常见三个坑:清空全部 transient 导致缓存雪崩、删掉”未使用的表”误伤其他程序、在业务高峰执行导致锁表超时。低峰期跑,逐项确认,第一次先在测试库试。
更新频繁的站每季度一次,纯展示站每半年一次。另外三个时间点顺手清:迁移之前、大版本升级之前、发现后台明显变慢时。设置了修订上限之后增量很小,不必更频繁。
取决于原来的状态。一个 autoload 超过 2MB 的站,清理后首字节时间下降几百毫秒是常见的;本来就健康的站,提升可能只有几十毫秒。它属于基础卫生,不是性能优化的主力。真正决定速度的是缓存策略、图片体积与服务器线路,这些在WordPress 速度优化里展开。
后台越来越慢,导出越来越大
先做一次体检再决定动不动手
把数据库大小、表清单和主机配置发给我们,可以先出一份只读诊断:哪张表异常、autoload 是否超标、有没有可安全清理的存量。确认之后再排清理窗口,全程有备份兜底。相关阅读:数据库报错处理、备份与恢复、WordPress 托管维护。
电话/微信 13280692153 邮箱 web@wordpressx.com 地址 山东省淄博市张店区电子产业创新园 B 座