如何加速WordPress中的SQL_CALC_FOUND_ROWS慢查询?
MariaDB慢查询优化方案
问题背景
慢查询日志中频繁出现以下耗时查询,执行时间5秒+,扫描44万行仅返回5条结果:
Time: 221202 11:46:57 Query_time: 5.022055 Lock_time: 0.000082 Rows_sent: 5 Rows_examined: 447119 Rows_affected: 0 Bytes_sent: 141 SELECT SQL_CALC_FOUND_ROWS ab_posts.ID FROM ab_posts LEFT JOIN ab_postmeta ON ( ab_posts.ID = ab_postmeta.post_id AND ab_postmeta.meta_key = 'cid' ) LEFT JOIN ab_postmeta AS mt1 ON ( ab_posts.ID = mt1.post_id ) WHERE 1=1 AND ( ab_postmeta.post_id IS NULL AND mt1.meta_key = '_json_file' ) AND ab_posts.post_type = 'listings' AND ((ab_posts.post_status = 'publish')) GROUP BY ab_posts.ID ORDER BY ab_posts.post_date DESC LIMIT 0, 5;
该查询由WordPress核心文件wp-includes\class-wp-query.php生成,对应代码片段:
$found_rows = ''; if ( ! $q['no_found_rows'] && ! empty( $limits ) ) { $found_rows = 'SQL_CALC_FOUND_ROWS'; } $old_request = " SELECT $found_rows $distinct $fields FROM {$wpdb->posts} $join WHERE 1=1 $where $groupby $orderby $limits ";
优化步骤
1. 针对性创建复合索引(核心优化)
给ab_posts表加复合索引
CREATE INDEX idx_posts_type_status_date ON ab_posts(post_type, post_status, post_date DESC, ID);
- 作用:快速过滤
post_type='listings'和post_status='publish'的记录,直接按post_date DESC排序(避免额外排序开销),同时ID字段覆盖查询,无需回表取数据。
给ab_postmeta表加复合索引
CREATE INDEX idx_meta_postid_key ON ab_postmeta(post_id, meta_key);
- 作用:同时支持
post_id+meta_key的查询,能快速定位到cid和_json_file对应的记录,大幅减少关联查询的扫描行数。
2. 关闭SQL_CALC_FOUND_ROWS减少额外开销
SQL_CALC_FOUND_ROWS会让数据库扫描所有符合条件的行来统计总记录数,哪怕只返回5条数据。如果页面不需要显示总页数/总条数(比如无限滚动),在WP_Query参数里添加:
'no_found_rows' => true
这样就不会生成SQL_CALC_FOUND_ROWS,直接砍掉大量扫描开销。
3. 重构查询逻辑(可选,进一步提速)
原查询的左连接+分组写法可以替换为更高效的EXISTS/NOT EXISTS,同时去掉多余的GROUP BY(ID是主键,分组无意义):
SELECT ab_posts.ID FROM ab_posts WHERE ab_posts.post_type = 'listings' AND ab_posts.post_status = 'publish' AND EXISTS (SELECT 1 FROM ab_postmeta WHERE post_id = ab_posts.ID AND meta_key = '_json_file') AND NOT EXISTS (SELECT 1 FROM ab_postmeta WHERE post_id = ab_posts.ID AND meta_key = 'cid') ORDER BY ab_posts.post_date DESC LIMIT 0,5;
这种写法让数据库可以提前终止子查询扫描,比左连接效率更高。
4. 清理冗余索引
检查ab_posts表是否存在post_type、post_status的单字段索引,复合索引已经覆盖这些场景,冗余的单字段索引可以删除,避免索引维护开销。
内容的提问来源于stack exchange,提问作者lsbtqba555
相关产品推荐
相关产品推荐

