当 WordPress 运行缓慢却找不到明显原因时,罪魁祸首往往是数据库慢查询——一条 MySQL 处理时间过长的 SQL 语句。每次 WordPress 页面浏览都会触发数十条数据库查询:加载文章、评论、小部件数据、插件选项等。即使链路中只有一条慢查询,也会明显提升 TTFB(首字节时间),在高负载下尤为如此。

本指南将引导您完成一套系统化的排查流程:启用 MySQL 慢查询日志、读取分析结果、使用 EXPLAIN 分析执行计划、优化数据库表,以及清理数据库臃肿——这套方法适用于共享主机和 VPS 环境。

WordPress 数据库查询为何变慢

WordPress 以 MySQL 作为主要数据存储。每个传入请求遵循以下流程:PHP 引导 → wp-config.php → MySQL 连接 → 数据检索(文章、选项、元数据)→ HTML 渲染 → 响应。数据库步骤耗时最长,因为 PHP 需要多次往返 MySQL。

WordPress 慢查询最常见的根本原因:

升级硬件或更换主机方案很少是正确的第一步。目标是找出哪些具体查询很慢以及原因所在,然后解决根本原因。

启用 MySQL 慢查询日志

第一个诊断步骤是开启慢查询日志,捕获超过时间阈值的语句。根据服务器访问权限,有两种方法。

方法一 — 通过 MySQL 控制台运行时配置(临时,无需重启)

适用于可以访问 phpMyAdmin 但无法编辑服务器配置文件的共享主机:

-- 启用慢查询日志
SET GLOBAL slow_query_log = 'ON';

-- 标记执行时间超过 1 秒的查询
SET GLOBAL long_query_time = 1;

-- 设置日志文件路径
SET GLOBAL slow_query_log_file = '/tmp/mysql-slow.log';

-- 同时记录未使用索引的查询(强烈推荐)
SET GLOBAL log_queries_not_using_indexes = 'ON';

这些设置在 MySQL 重启时会恢复,因此适合临时调试会话。

方法二 — 编辑 my.cnf(永久生效,适用于具有 root 权限的 VPS)

[mysqld]
slow_query_log = 1
long_query_time = 1
slow_query_log_file = /var/log/mysql/slow.log
log_queries_not_using_indexes = 1
min_examined_row_limit = 100

重启 MySQL 使更改生效:

sudo systemctl restart mysql
# 或在旧系统上:
sudo service mysqld restart

读取和分析慢查询日志

在日志运行一段真实流量后,使用内置工具 mysqldumpslow 进行分析:

# 按总执行时间排列的前 10 条最慢查询
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 执行频率最高的前 10 条慢查询
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log

如需更深入的分析,安装 Percona Toolkit 并使用 pt-query-digest:

# 在 Ubuntu/Debian 上安装
sudo apt-get install percona-toolkit

# 分析日志
pt-query-digest /var/log/mysql/slow.log

输出结果会将相似查询分组,显示总执行时间、每次调用的平均时间以及检查的行数。优先关注总执行时间最高的查询——这些查询对网站速度的实际影响最大。

使用 EXPLAIN 了解查询执行计划

识别出慢查询后,在其前面运行 EXPLAIN,查看 MySQL 计划如何执行它。这能揭示是否使用了索引:

EXPLAIN SELECT * FROM wp_postmeta
WHERE meta_key = '_thumbnail_id'
AND post_id IN (
  SELECT ID FROM wp_posts WHERE post_status = 'publish'
);

EXPLAIN 输出中需要重点检查的列:

列名 含义 理想值 警告值
type MySQL 访问表的方式 const, ref, range ALL(全表扫描)
rows MySQL 需要检查的预估行数 接近结果集大小 数十万行
key 本步骤选择的索引 索引名称 NULL(未使用索引)
Extra 额外的执行详情 Using index Using filesort, Using temporary

当您看到 type = ALL 且 key = NULL 时,MySQL 正在读取表中的每一行来查找匹配项。在 WHERE 或 JOIN 子句使用的列上添加适当的索引,通常可将执行时间缩短一个数量级。

使用 Query Monitor 插件

如果无法直接访问 MySQL,免费的 Query Monitor 插件可以在 WordPress 后台提供同等级别的分析。从插件 > 添加新插件中安装并启用它。

Query Monitor 能够显示的信息:

-- Query Monitor 捕获的常见重复查询示例
SELECT option_value FROM wp_options WHERE option_name = 'siteurl'
-- 当插件未能缓存结果时,此单条查询可能每页运行 5–10 次

当您发现慢查询或重复查询时,Query Monitor 会提供调用该查询的代码文件名和行号,让您可以直接找到源头,向插件作者报告问题或寻找替代方案。

重要提示:Query Monitor 会为每次页面加载增加额外开销。调查完成后请务必停用它——切勿在生产环境中保持调试插件运行。

优化前先清理数据库臃肿

对仍存有大量过期数据的表运行 OPTIMIZE TABLE 效果有限。应先清理数据,再进行优化。以下是 WordPress 网站最有效的清理查询。

删除旧的文章修订版本

-- 检查修订版本数量
SELECT COUNT(*) FROM wp_posts WHERE post_type = 'revision';

-- 删除所有修订版本
DELETE FROM wp_posts WHERE post_type = 'revision';

-- 清理遗留的孤立 postmeta 行
DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL;

在 wp-config.php 中限制未来修订版本数量

在 wp-config.php 中 That's all, stop editing! 注释之前添加以下行,以防止未来产生无限制的修订版本:

// 每篇文章仅保留最近 3 个修订版本
define('WP_POST_REVISIONS', 3);

清除过期临时数据

-- 删除已超时的临时数据(超时时间已过的值)
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 REPLACE(option_name, '_transient_', '_transient_timeout_')
    NOT IN (
        SELECT option_name
        FROM (SELECT option_name FROM wp_options) AS tmp
    );

删除垃圾评论和孤立评论元数据

-- 统计垃圾评论数量
SELECT COUNT(*) FROM wp_comments WHERE comment_approved = 'spam';

-- 删除垃圾评论
DELETE FROM wp_comments WHERE comment_approved = 'spam';

-- 清理孤立的 commentmeta
DELETE FROM wp_commentmeta
WHERE comment_id NOT IN (SELECT comment_ID FROM wp_comments);

执行 DELETE 语句前务必备份。 执行任何批量删除操作前,请从 phpMyAdmin 导出数据库,或使用 UpdraftPlus 等插件进行备份。先以 SELECT COUNT(*) 运行每条查询,验证将影响的行数,确认数量正确后再改用 DELETE。这种两步操作法已帮助许多网站避免了意外数据丢失。

运行 OPTIMIZE TABLE

清理完成后,运行 OPTIMIZE TABLE 对表进行碎片整理,并回收被删除行释放的空间。对 wp_posts、wp_postmeta、wp_options 和 wp_comments 效果最为显著。

通过 phpMyAdmin

  1. 打开 phpMyAdmin 并选择您的 WordPress 数据库。
  2. 点击 结构 选项卡,勾选所有表(或选择特定表)。
  3. 在底部的"已选项目"下拉菜单中,选择 优化表。
  4. 等待所有行显示状态:OK。

通过 MySQL 命令行

-- 优化特定高流量表
OPTIMIZE TABLE wp_posts, wp_postmeta, wp_options, wp_comments;

-- 或一次性优化数据库中的所有表
mysqlcheck -u root -p --optimize your_wordpress_db

添加索引以加速常见 WordPress 查询

如果 EXPLAIN 显示 key = NULL,添加有针对性的索引往往是最高效的单一修复措施。wp_postmeta 表经常同时按 meta_key 和 meta_value 进行查询,但 WordPress 默认 schema 只在 meta_key 上有单列索引。

-- 检查现有索引
SHOW INDEX FROM wp_postmeta;

-- 添加复合索引,用于同时按键和值过滤的查询
ALTER TABLE wp_postmeta
ADD INDEX idx_key_value (meta_key, meta_value(20));

-- 在 autoload 列添加索引以加速 WordPress 启动
ALTER TABLE wp_options ADD INDEX idx_autoload (autoload);

-- 审计自动加载选项的总大小(应保持在 ~800KB 以下)
SELECT SUM(LENGTH(option_value)) AS autoload_bytes
FROM wp_options WHERE autoload = 'yes';

如果 autoload_bytes 超过 800,000(约 800KB),WordPress 在每次页面请求时加载的数据过多。利用结果找出哪个插件添加了最大的自动加载选项,然后配置其不自动加载,或寻找替代方案。

wp-config.php 额外调优

几个 wp-config.php 常量直接控制 WordPress 在每次保存操作时向数据库写入的数据量:

// 将文章修订版本限制为 3 个
define('WP_POST_REVISIONS', 3);

// 将自动保存间隔从 60 秒增加到 300 秒(减少写入频率)
define('AUTOSAVE_INTERVAL', 300);

// 启用对象缓存(缓存插件如 LiteSpeed Cache 所需)
define('WP_CACHE', true);

// 将垃圾桶自动清空时间从 30 天改为 7 天
define('EMPTY_TRASH_DAYS', 7);

// 确保完整 Unicode 支持的正确字符集
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', 'utf8mb4_unicode_ci');

常见问题

什么是 WordPress 慢查询?它如何影响我的网站?

慢查询是指执行时间超过设定阈值的 MySQL SQL 语句。MySQL 默认为 10 秒,但实际上任何超过 1–2 秒的查询都被视为慢查询。每次 WordPress 页面浏览都会触发数十条数据库查询。即使是一条慢查询,也会明显增加 TTFB,尤其是在高流量情况下。慢查询还会使数据库服务器的 CPU 和内存使用量激增,影响同一主机上所有其他页面的性能。

如何启用 MySQL 慢查询日志?

在共享主机上,打开 phpMyAdmin 并运行 SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;——这些设置是临时的。在具有 root 权限的 VPS 上,在 my.cnf 的 [mysqld] 部分添加 slow_query_log=1、long_query_time=1 和 slow_query_log_file=/var/log/mysql/slow.log,然后重启 MySQL 使其永久生效。使用 mysqldumpslow 或 pt-query-digest 分析生成的日志。

哪个 WordPress 插件最适合分析数据库查询性能?

Query Monitor(免费)是 WordPress 插件目录中功能最强的选项。它显示每次页面加载的所有数据库查询及执行时间,并通过 PHP 堆栈跟踪指向触发查询的来源插件或主题,还会标出在单次请求中多次触发的重复查询。在生产环境中请务必停用调试插件,因为它们会大幅增加每次请求的开销。

我应该多久优化一次 WordPress 数据库?

对于高活跃度网站——每天发布内容的博客或持续有订单的 WooCommerce 商店——至少每月优化一次。频繁编辑内容的网站会快速积累文章修订版本和过期临时数据。设置 wp-cron 或服务器定时任务,自动清理修订版本、垃圾评论和过期临时数据。最需要定期优化的表是 wp_posts 和 wp_postmeta,因为它们具有最频繁的写入和删除操作。

针对 WordPress 优化的主机服务

AsiaGB 主机支持 PHP 8.3、MySQL、LiteSpeed Cache 和 WordPress Toolkit——低至 500 泰铢/年。

查看主机方案