WordPress 查询性能优化 – 禁用 SQL_CALC_FOUND_ROWS

WordPress 祖传使用SQL_CALC_FOUND_ROWS进行数量统计并计算分页,但是这个查询语句在大数据量 (W+) 的情况下是很慢的,一个比较好的解决方法是将其替换成更为现代的COUNT语句。

尽管这个问题在几年前就已经通过 WordPress 的 Ticket 系统报给了 WordPress 官方,但是似乎因历史遗留原因一直未见修复。
(正常,类似没修复的 Ticket 还有很多)

下面是对此写的一个插件,用于在官方修复前临时解决此问题:

<?PHP
/**
 * Plugin Name: Fix WordPress Slow Queries
 * Description: Fix WordPress Slow Queries
 * Author: Mahdi Akrami
 * Version: 1.0.0
 */

class FIX_WP_SLOW_QUERY {

        public static function init () {

                /**
                 * WP_Query
                 */

                add_filter ( 'found_posts_query', [ __CLASS__, 'add_found_rows_query' ], 999, 2 );

                add_filter ( 'posts_request_ids', [ __CLASS__, 'remove_found_rows_query' ], 999 );

                add_filter ( 'posts_pre_query', function ( $posts, \WP_Query $query ) {

                        $query->request = self::remove_found_rows_query ( $query->request );

                        return $posts;
                }, 999, 2 );

                add_filter ( 'posts_clauses', function ( $clauses, \WP_Query $wp_query ) {

                        $wp_query->fw_clauses = $clauses;

                        return $clauses;
                }, 999, 2 );

        }

        public static function remove_found_rows_query ( $sql ) {

                return str_replace ( ' SQL_CALC_FOUND_ROWS ', '', $sql );
        }

        public static function add_found_rows_query ( $sql, WP_Query $query ) {

                global $wpdb;

                $distinct = $query->fw_clauses['distinct'] ?? '';
                $join     = $query->fw_clauses['join'] ?? '';
                $where    = $query->fw_clauses['where'] ?? '';
                $groupby  = $query->fw_clauses['groupby'] ?? '';

                $count = 'COUNT (*)';

                if ( ! empty ( $groupby ) ) {
                        $count = "COUNT ( distinct $groupby )";
                }

                return "
                        SELECT $distinct $count
                        FROM {$wpdb->posts} $join
                        WHERE 1=1 $where
                ";
        }

}

FIX_WP_SLOW_QUERY::init ();