在 phpMyAdmin 里执行(非常关键)
SHOW FULL PROCESSLIST;
可以看到
SELECT MAX(p.post_modified_gmt) as last_modi..
看更详情
二、为什么这条 SQL 会“极其致命”(技术解剖)
我们拆解你这条 SQL,你就明白为什么 MySQL 会炸。
1️⃣ 核心结构(这是性能灾难)
SELECT MAX(p.post_modified_gmt)
FROM wp_posts p
WHERE p.post_status = ‘publish’
AND p.ID IN (
SELECT tr.object_id
FROM wp_term_relationships tr
JOIN wp_term_taxonomy tt
WHERE tt.term_id IN (
SELECT term_id
FROM wp_term_taxonomy
WHERE parent = ‘28446’
)
)
2️⃣ 三个致命点
❌ 致命点一:ID IN (子查询) + 多层嵌套
- MySQL 5.7 对这种写法 优化能力很弱
- 基本等同于:
- 先扫 taxonomy
- 再扫 relationships
- 再反查 posts
- 无法有效利用索引
❌ 致命点二:这是“分类级别”的查询
这句:
WHERE tt.parent = '28446' 意味着:
- 一个父分类
- 下面可能有 几十 / 几百 / 上千篇文章
- 每次查询 = 扫整个分类下所有文章
❌ 致命点三:被高频触发
这类查询一般会在以下地方反复出现:
- 分类页
<head>(schema / lastmod) - sitemap(分类 sitemap)
- REST API(分类接口)
- 缓存失效时并发请求
👉 一次请求还好,并发一来,CPU 直接起飞
三、为什么你现在 MySQL 会 300% CPU
结合你之前的截图,可以得出完整因果链:
- 分类 last_modified 是“实时算”的
- 没有合适索引
- MySQL 5.7 + IN 子查询
- wp-json / sitemap / 分类页 被反复访问
- → mysqld 单线程满载 × 多并发
- → CPU 300%
这是一个非常标准的 WordPress 性能事故模型。
四、立刻能“止血 + 治本”的方案(照顺序做)
✅ 第一步(必须做):补齐正确索引(这是根)
直接执行:
ALTER TABLE wp_posts
ADD INDEX idx_status_modified_id (post_status, post_modified_gmt, ID);
ALTER TABLE wp_term_relationships
ADD INDEX idx_object_id (object_id);
ALTER TABLE wp_term_taxonomy
ADD INDEX idx_parent_term (parent, term_id);
这一步做完:
- 同样的 SQL
- 执行时间会从 秒级 → 毫秒级
- MySQL CPU 会立刻明显下降
👉 这是数据库层的“根治”
✅ 第二步(强烈建议):禁止“实时计算分类 last_modified”
不管你用什么主题 / 插件,找以下功能并关闭:
- 分类 schema 的
dateModified - 分类 sitemap 的动态 lastmod
- “auto detect last updated post in category”
如果找不到,80% 在主题里。
✅ 第三步(验证是否 REST API 在触发)
临时在 nginx 里加(测试用):
location ~* ^/wp-json/wp/v2/categories { return 403;
} 如果一加:
- MySQL CPU 明显下降
👉 那就说明 API 在疯狂算这个分类
五、如果你想“一劳永逸”(工程级方案)
🧠 正确做法(专业站点都这么干)
分类的 last_modified 不该实时算,而应该“预计算 + 缓存”
思路:
- 文章发布 / 更新时
- 更新该分类的一个 meta / option
- 前端直接读值,不跑 SQL
这是我给客户做大站时的标准解法。
六、一句话总结(给你吃颗定心丸)
你现在的问题已经完全定位清楚:
是“分类维度 last_modified 的实时 SQL”,不是 SEO 插件、不是攻击、不是服务器不行。
你现在只要:
- 补索引(立刻见效)
- 关掉分类实时 lastmod
- 必要时挡 wp-json 分类接口
这台服务器就能马上“活过来”。






