一个跑了三年的 WordPress 站,数据库 2.3 G。
导出要半个小时,导入经常超时,后台打开文章列表转圈十几秒。
拆开看,文章表 wp_posts 才 80 M,剩下的 2.2 G 全在 wp_options 和 wp_postmeta 里。
这两个表是 WordPress 最容易被撑爆的地方,而且大部分数据是垃圾。
先看谁在占地方
进 phpMyAdmin 或者命令行,按大小排序:
SELECT table_name AS 表名,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS 大小MB,
table_rows AS 行数
FROM information_schema.tables
WHERE table_schema = '数据库名'
ORDER BY (data_length + index_length) DESC
LIMIT 10;
我的结果:
wp_options 1840.22 120万行
wp_postmeta 310.55 45万行
wp_posts 82.13 3200行
wp_termmeta 8.44 1.2万行
wp_options 一千八百多 M,一百二十万行。正常的站这个表应该在几 M 到几十 M。
wp_options 为什么会这么大
三个原因。
一、autoload 数据太多。
WordPress 每次请求都会把 autoload = yes 的 option 全部加载进内存。
SELECT COUNT(*), ROUND(SUM(LENGTH(option_value))/1024/1024, 2) AS MB
FROM wp_options WHERE autoload = 'yes';
健康的站这条查询应该返回几百行、几 M 以内。我那次是一万两千行、三百多 M。
原因是插件卸载不干净,每个插件都会往 options 里塞配置,删了插件配置还在,而且 autoload 还是 yes。
二、transient 过期不清理。
WordPress 的临时缓存存在 wp_options 里,键名是 _transient_ 开头。正常会自己过期删除,但如果站点流量低,没有请求触发清理,就会一直堆着。
SELECT COUNT(*) FROM wp_options
WHERE option_name LIKE '_transient_%' OR option_name LIKE '_site_transient_%';
我那次是 60 多万条。
三、某个插件把日志写进了 options。
这是我这次的主因。一个统计插件,把每次访问记录序列化后塞进 option 里,键名是 plugin_xxx_log_20250312 这种按天分的。
三年下来,一千多个 option,每个几百 K。
清理步骤
第一步,先备份。这步不做,后面别动手。
mysqldump -uroot -p 数据库名 wp_options > options_backup.sql
第二步,删过期的 transient。
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 NOT EXISTS (
SELECT 1 FROM (SELECT option_name AS n FROM wp_options
WHERE option_name LIKE '_transient_timeout_%') t
WHERE t.n = CONCAT('_transient_timeout_', SUBSTRING(wp_options.option_name, 12))
);
第二条 SQL 有点绕,简单说就是:把没有对应 timeout 记录的 transient 删掉,这些是"孤儿"。
如果嫌麻烦,装个插件 WP-Optimize,一键清理,效果好。
第三步,把不该 autoload 的关掉。
UPDATE wp_options SET autoload = 'no'
WHERE autoload = 'yes'
AND option_name NOT IN (
'siteurl','home','blogname','blogdescription','users_can_register',
'admin_email','start_of_week','use_balanceTags','use_smilies',
'require_name_email','comments_notify','posts_per_rss','rss_use_excerpt',
'mailserver_url','mailserver_login','mailserver_pass','mailserver_port',
'default_category','default_comment_status','default_ping_status',
'default_pingback_flag','posts_per_page','date_format','time_format',
'links_updated_date_format','comment_moderation','moderation_notify',
'permalink_structure','rewrite_rules','hack_file','blog_charset',
'moderation_keys','active_plugins','category_base','tag_base',
'advanced_edit','comment_max_links','gmt_offset','default_role',
'wp_page_for_privacy_policy','template','stylesheet','show_on_front',
'page_on_front','page_for_posts','db_version','upload_path',
'upload_url_path','thumbnail_size_w','thumbnail_size_h',
'medium_size_w','medium_size_h','large_size_w','large_size_h',
'image_default_link_type','image_default_size','image_default_align',
'close_comments_for_old_posts','close_comments_days_old',
'thread_comments','thread_comments_depth','page_comments',
'comments_per_page','default_comments_page','comment_order',
'sticky_posts','timezone_string','blog_public','fresh_site',
'WPLANG','widget_%','theme_mods_%','sidebars_widgets'
);
这个白名单是 WordPress 核心必须 autoload 的。漏了 rewrite_rules 会导致全站 404,漏了 active_plugins 会导致插件全失效。
第四步,清理插件残留。
SELECT option_name, LENGTH(option_value) AS len
FROM wp_options
ORDER BY len DESC
LIMIT 30;
把最大的三十条拉出来看键名,认不出来的搜一下,确认是哪个插件留下的,再删。
这一步要慢,删错了可能某个功能就没了。
结果
清理完,wp_options 从 1840 M 降到 68 M,行数从 120 万降到 1.8 万。
整站数据库 2.3 G → 460 M。
后台文章列表从 12 秒降到 1 秒多。首页 TTFB 从 1.8 秒降到 0.5 秒。
导出时间从 30 分钟降到 2 分钟,备份终于正常了。
预防
清理只是一次性的,不预防还会再涨。现在我做两件事:
一是每月跑一次清理 SQL,做成脚本挂 crontab。
二是装插件之前先看它往 options 里写什么,那种"每次访问都写一条日志到数据库"的插件,一律不装。
数据库膨胀从来不是突然发生的,是每天几百条垃圾慢慢堆出来的。等发现的时候,已经堆了三年。
1、本站所有资源均收集于互联网,分享目的仅限学习与参考。如有侵权,请联系 1685698671@qq.com 及时删除!
2、本站资源不保证完整性和安全性,下载后请自行检测。使用过程中出现的任何问题均与本站无关,敬请自行处理。
3、本站资源仅限个人学习研究使用,严禁用于任何违法违纪用途。因使用者违规使用产生的一切后果,由使用者自行承担,本站不承担任何责任。


评论(0)