关于 woocommerce-performance
面向 WooCommerce 管理者和开发者,提供排查与改善商店性能的实践指导。内容包括查询分析、对象缓存、数据库优化及定期清理。
主要功能
- 01使用 Query Monitor 分析查询
- 02配置 Redis 持久对象缓存
- 03优化 WooCommerce 数据库查询
- 04清理会话与临时数据
- 05检查并精简自动加载选项
适用场景
- 01排查商店页面加载缓慢
- 02降低 AJAX 请求造成的数据库负载
- 03处理膨胀的 WooCommerce 会话表
- 04减少 wp_options 自动加载开销
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ finsilabs/ awesome-ecommerce-skills --skill woocommerce-performance安装后在 Claude Code 中输入/woocommerce-performance确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
tile.jsonevals/database-cleanup-and-session-maintenance/criteria.jsontask.mdevals/query-optimization-and-n-1-prevention/criteria.jsontask.mdevals/redis-object-cache-configuration/criteria.jsontask.md详细介绍
WooCommerce 性能
概述
WooCommerce 性能问题通常源于五个方面:未建立索引的 meta 表导致产品查询开销高、无上限的 AJAX 购物车/结账请求、缺少持久化对象缓存、臃肿的 wp_options 自动加载数据,以及不断增长却未清理的 wp_woocommerce_sessions 和订单表。本技能涵盖性能分析、查询优化、Redis 对象缓存和定期维护流程。
何时使用本技能
- 商店页面在中等流量下(数百名并发用户)加载缓慢时
- WooCommerce AJAX 调用(添加到购物车、运费计算)期间服务器 CPU 使用率飙升时
- New Relic 或 Query Monitor 显示 MySQL 查询耗时是主要瓶颈时
wp_options表的自动加载数据超过 1–2 MB 时wp_woocommerce_sessions含有数百万行,导致会话查询变慢时- 在高流量商店中实施 Redis 或 Memcached 以减少 MySQL 负载时
核心说明
-
先用 Query Monitor 进行性能分析
安装 Query Monitor 插件,找出管理后台和前端的慢查询:
# Via WP-CLI wp plugin install query-monitor --activate请重点关注:
- 每次页面加载的查询数(超过 50 个就值得关注)
- 重复查询(同一查询多次运行)
- 慢查询(单个查询耗时超过 100ms)
- 大型结果集(返回数千行的查询)
在生产环境中进行性能分析时,启用 MySQL 慢查询日志:
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 0.5; SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; -
启用 Redis 持久化对象缓存
这是对 WooCommerce 影响最大的优化。如果没有它,每次页面加载都会从 MySQL 重新获取相同的产品数据:
# Install Redis server sudo apt install redis-server # Install the Redis Object Cache plugin wp plugin install redis-cache --activate wp redis enable在
wp-config.php中配置:define('WP_REDIS_HOST', '127.0.0.1'); define('WP_REDIS_PORT', 6379); define('WP_REDIS_DATABASE', 0); define('WP_REDIS_TIMEOUT', 1); define('WP_REDIS_READ_TIMEOUT', 1); define('WP_REDIS_MAXTTL', 86400); // 24 hours max TTL // Selective cache groups — exclude user sessions from Redis (they change constantly) define('WP_REDIS_IGNORED_GROUPS', ['wc_session_id', 'counts', 'plugins']); -
优化 WooCommerce 专用数据库查询
<?php // Add missing indexes for common WooCommerce product queries // Run once via WP-CLI: wp eval-file add-indexes.php global $wpdb; // Index for product meta queries (stock status, visibility, price) $wpdb->query(" ALTER TABLE {$wpdb->postmeta} ADD INDEX wc_product_meta_lookup (meta_key(32), meta_value(64)) "); // Index for order meta queries $wpdb->query(" ALTER TABLE {$wpdb->postmeta} ADD INDEX wc_order_customer_lookup (meta_key(32), meta_value(100)) ");使用 WooCommerce 的 HPOS(高性能订单存储)将订单移出文章 meta:
// wp-config.php — enable HPOS (WooCommerce 7.1+) // This is configured via WooCommerce Settings → Advanced → Features // Enables dedicated order tables: wp_wc_orders, wp_wc_order_items, etc.# Check HPOS status wp wc hpos status # Migrate orders to HPOS wp wc hpos migrate --batch-size=500 -
清理 transient、会话和日志表
<?php // Scheduled cleanup — run daily via Action Scheduler add_action('my_plugin_daily_cleanup', function () { global $wpdb; // Delete expired WooCommerce sessions (older than 48 hours) $expiry_threshold = time() - (48 * HOUR_IN_SECONDS); $wpdb->query($wpdb->prepare(" DELETE FROM {$wpdb->prefix}woocommerce_sessions WHERE session_expiry < %d LIMIT 5000 ", $expiry_threshold)); // Delete expired transients $wpdb->query(" DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_%' AND option_value < UNIX_TIMESTAMP() LIMIT 5000 "); $wpdb->query(" DELETE t FROM {$wpdb->options} t LEFT JOIN {$wpdb->options} e ON e.option_name = REPLACE(t.option_name, '_transient_', '_transient_timeout_') WHERE t.option_name LIKE '_transient_%' AND e.option_id IS NULL LIMIT 5000 "); // Rotate WooCommerce logs older than 30 days $wpdb->query(" DELETE FROM {$wpdb->prefix}woocommerce_log WHERE timestamp < DATE_SUB(NOW(), INTERVAL 30 DAY) LIMIT 10000 "); }); // Register the scheduled event add_action('init', function () { if (!as_next_scheduled_action('my_plugin_daily_cleanup')) { as_schedule_recurring_action(strtotime('tomorrow midnight'), DAY_IN_SECONDS, 'my_plugin_daily_cleanup'); } }); -
优化 wp_options 自动加载表
每次页面请求都会加载自动加载选项。自动加载数据臃肿会造成显著开销:
-- Find large autoloaded options SELECT option_name, LENGTH(option_value) as size_bytes FROM wp_options WHERE autoload = 'yes' ORDER BY LENGTH(option_value) DESC LIMIT 30;<?php // Fix: Store plugin data as transients or post meta instead of autoloaded options // Bad — autoloaded, loaded on every request update_option('my_plugin_product_cache', $large_array, true); // Good — not autoloaded update_option('my_plugin_product_cache', $large_array, false); // Better — use transient with expiry set_transient('my_plugin_product_cache', $large_array, HOUR_IN_SECONDS); // Disable autoload for existing options global $wpdb; $wpdb->update( $wpdb->options, ['autoload' => 'no'], ['option_name' => 'woocommerce_attribute_taxonomies'] );
示例
为产品循环添加片段缓存
<?php
// Cache rendered product card HTML in Redis to avoid re-rendering
function render_product_card_cached(int $product_id): string {
$cache_key = "product_card_{$product_id}_" . get_locale();
$cached = wp_cache_get($cache_key, 'product_cards');
if ($cached !== false) {
return $cached;
}
$product = wc_get_product($product_id);
if (!$product) return '';
ob_start();
wc_get_template('content-product.php', ['product' => $product]);
$html = ob_get_clean();
// Cache for 30 minutes; invalidate on product update
wp_cache_set($cache_key, $html, 'product_cards', 30 * MINUTE_IN_SECONDS);
return $html;
}
// Purge cache when product is updated
add_action('woocommerce_update_product', function (int $product_id) {
wp_cache_delete("product_card_{$product_id}_" . get_locale(), 'product_cards');
// Also delete all locale variants
wp_cache_flush_group('product_cards');
});
检测并修复 N+1 产品查询
<?php
// Bad — triggers N+1 queries (one per product in loop)
$product_ids = wc_get_featured_product_ids();
foreach ($product_ids as $id) {
$product = wc_get_product($id); // <-- separate query for each product
echo $product->get_name();
}
// Good — prime the cache before the loop
$product_ids = wc_get_featured_product_ids();
// Pre-warm the object cache with all products in a single query
$products = array_map('wc_get_product', $product_ids); // Still N queries without this:
// Better — use WC_Product_Query with ID filter (single query)
$products = wc_get_products([
'include' => $product_ids,
'limit' => count($product_ids),
'return' => 'objects',
]);
foreach ($products as $product) {
echo $product->get_name(); // data already loaded
}
最佳实践
- 在 WooCommerce 7.1 及以上版本的商店中启用 HPOS(高性能订单存储)——它会将订单数据移至带有适当索引的专用表,从而消除订单方面的
wp_postmeta瓶颈 - 优先添加 Redis/Memcached 对象缓存——它可消除 WordPress 和 WooCommerce 每次请求都会产生的冗余 MySQL 查询,通常能将数据库负载降低 60–80%
- 通过 Action Scheduler 在低峰时段运行清理——批量执行 DELETE 操作(每次最多处理 5000 行),避免清理期间长时间锁表
- 仅在开发环境中将
WP_DEBUG_LOG与SAVEQUERIES配合使用——在生产环境启用这些选项会严重影响性能;生产环境性能分析请使用 APM 工具(New Relic、Datadog) - 对管理后台的订单查询进行分页——一次加载全部订单(
posts_per_page: -1)会锁定 MySQL 并导致超时;始终使用paged,并将posts_per_page设为不超过 100 - 设置
WP_REDIS_IGNORED_GROUPS,将易变数据(购物车、会话计数器)排除在 Redis 缓存之外,避免高流量结账页面出现缓存击穿 - 每周监控
wp_options表大小——如果自动加载数据超过 800KB,则设置告警;常见原因包括将大型数组存储为自动加载选项的插件
常见陷阱
| 问题 | 解决方案 |
|---|---|
| Redis 缓存未能减少 MySQL 查询 | 在 Query Monitor 中检查 wp_cache_get 命中率——命中率低意味着缓存键失效过于频繁,或 TTL 太短 |
| 清理查询导致表级锁 | 在 DELETE 查询中使用行级 LIMIT 子句(每次最多 5000 行),并安排在流量较低的时段运行 |
| HPOS 迁移导致第三方插件无法正常工作 | 启用 HPOS 前,审查所有插件中对 get_post_meta(order_id, ...) 的使用情况——这些调用必须更新为使用 $order->get_meta() |
| 尽管有索引,商品列表仍然很慢 | 检查 wc_lookup_table_enabled 是否已启用;WooCommerce 3.7+ 引入的 wp_wc_product_meta_lookup 表可显著加快商品查询 |
| 导入商品后对象缓存过时 | 在批量导入脚本结束时调用 wp_cache_flush() 或 wp_cache_flush_group('products'),以使过时的商品缓存失效 |
| 清理后会话表仍然不断增长 | 确保 WC_Session_Handler 使用数据库后端(而非 PHP 会话);默认的基于 Cookie 的会话不会创建数据库行,但自定义插件可能会强制使用数据库会话 |
相关技能
- @woocommerce-plugin-development
- @woocommerce-rest-api
- @database-query-optimization
- @caching-strategies
- @infrastructure-performance
评论
支持 Markdown