WordPress.org

Make WordPress Core

Changeset 34310


Ignore:
Timestamp:
09/18/2015 07:27:39 PM (4 years ago)
Author:
boonebgorges
Message:

Split the comment query.

WP_Comment_Query now fetches comments in two stages: (1) a query to get the
IDs of comments matching the query vars, and (2) a query to populate the
objects corresponding to the matched IDs. The two queries are cached
separately, so that sites with persistent object caches will continue to have
complete cache coverage for normal comment queries.

Splitting the query allows our cache strategy to be more modest and precise, as
full comment data is only stored once per comment. It also makes it possible
to introduce logic for paginated threading, which is necessary to address
certain performance problems.

See #8071.
data is only stored once per comment, instead of along with

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-comment-query.php

    r34268 r34310  
    3434     */
    3535    public $meta_query = false;
     36
     37    /**
     38     * Metadata query clauses.
     39     *
     40     * @since 4.4.0
     41     * @access protected
     42     * @var array
     43     */
     44    protected $meta_query_clauses;
    3645
    3746    /**
     
    262271        global $wpdb;
    263272
    264         $groupby = '';
    265 
    266273        $this->parse_query();
    267274
     
    282289        $this->meta_query->parse_query_vars( $this->query_vars );
    283290        if ( ! empty( $this->meta_query->queries ) ) {
    284             $meta_query_clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this );
     291            $this->meta_query_clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this );
    285292        }
    286293
     
    292299            wp_cache_set( 'last_changed', $last_changed, 'comment' );
    293300        }
    294         $cache_key = "get_comments:$key:$last_changed";
    295 
    296         if ( $cache = wp_cache_get( $cache_key, 'comment' ) ) {
    297             $this->comments = $cache;
     301        $cache_key = "get_comment_ids:$key:$last_changed";
     302
     303        $comment_ids = wp_cache_get( $cache_key, 'comment' );
     304        if ( false === $comment_ids ) {
     305            $comment_ids = $this->get_comment_ids();
     306            wp_cache_add( $cache_key, $comment_ids, 'comment' );
     307        }
     308
     309        // If querying for a count only, there's nothing more to do.
     310        if ( $this->query_vars['count'] ) {
     311            // $comment_ids is actually a count in this case.
     312            return intval( $comment_ids );
     313        }
     314
     315        $comment_ids = array_map( 'intval', $comment_ids );
     316
     317        if ( 'ids' == $this->query_vars['fields'] ) {
     318            $this->comments = $comment_ids;
    298319            return $this->comments;
    299320        }
    300321
     322        _prime_comment_caches( $comment_ids, $this->query_vars['update_comment_meta_cache'] );
     323
     324        // Fetch full comment objects from the primed cache.
     325        $_comments = array();
     326        foreach ( $comment_ids as $comment_id ) {
     327            if ( $_comment = wp_cache_get( $comment_id, 'comment' ) ) {
     328                $_comments[] = $_comment;
     329            }
     330        }
     331
     332        /**
     333         * Filter the comment query results.
     334         *
     335         * @since 3.1.0
     336         *
     337         * @param array            $results  An array of comments.
     338         * @param WP_Comment_Query &$this    Current instance of WP_Comment_Query, passed by reference.
     339         */
     340        $_comments = apply_filters_ref_array( 'the_comments', array( $_comments, &$this ) );
     341
     342        // Convert to WP_Comment instances
     343        $comments = array_map( 'get_comment', $_comments );
     344
     345        $this->comments = $comments;
     346        return $this->comments;
     347    }
     348
     349    /**
     350     * Used internally to get a list of comment IDs matching the query vars.
     351     *
     352     * @since 4.4.0
     353     * @access protected
     354     *
     355     * @global wpdb $wpdb
     356     */
     357    protected function get_comment_ids() {
     358        global $wpdb;
     359
     360        $groupby = '';
    301361        $where = array();
    302362
     
    472532            $fields = 'COUNT(*)';
    473533        } else {
    474             switch ( strtolower( $this->query_vars['fields'] ) ) {
    475                 case 'ids':
    476                     $fields = "$wpdb->comments.comment_ID";
    477                     break;
    478                 default:
    479                     $fields = "*";
    480                     break;
    481             }
     534            $fields = "$wpdb->comments.comment_ID";
    482535        }
    483536
     
    626679        }
    627680
    628         if ( ! empty( $meta_query_clauses ) ) {
    629             $join .= $meta_query_clauses['join'];
     681        if ( ! empty( $this->meta_query_clauses ) ) {
     682            $join .= $this->meta_query_clauses['join'];
    630683
    631684            // Strip leading 'AND'.
    632             $where[] = preg_replace( '/^\s*AND\s*/', '', $meta_query_clauses['where'] );
     685            $where[] = preg_replace( '/^\s*AND\s*/', '', $this->meta_query_clauses['where'] );
    633686
    634687            if ( ! $this->query_vars['count'] ) {
     
    678731
    679732        if ( $this->query_vars['count'] ) {
    680             return $wpdb->get_var( $this->request );
    681         }
    682 
    683         if ( 'ids' == $this->query_vars['fields'] ) {
    684             $this->comments = $wpdb->get_col( $this->request );
    685             return array_map( 'intval', $this->comments );
    686         }
    687 
    688         $results = $wpdb->get_results( $this->request );
    689         /**
    690          * Filter the comment query results.
    691          *
    692          * @since 3.1.0
    693          *
    694          * @param array            $results  An array of comments.
    695          * @param WP_Comment_Query &$this    Current instance of WP_Comment_Query, passed by reference.
    696          */
    697         $_comments = apply_filters_ref_array( 'the_comments', array( $results, &$this ) );
    698 
    699         // Convert to WP_Comment instances
    700         $comments = array_map( 'get_comment', $_comments );
    701 
    702         wp_cache_add( $cache_key, $comments, 'comment' );
    703         if ( '*' === $fields ) {
    704             update_comment_cache( $comments, $this->query_vars['update_comment_meta_cache'] );
    705         }
    706 
    707         $this->comments = $comments;
    708         return $this->comments;
     733            return intval( $wpdb->get_var( $this->request ) );
     734        } else {
     735            $comment_ids = $wpdb->get_col( $this->request );
     736            return array_map( 'intval', $comment_ids );
     737        }
    709738    }
    710739
  • trunk/src/wp-includes/comment-functions.php

    r34270 r34310  
    23782378
    23792379/**
     2380 * Adds any comments from the given IDs to the cache that do not already exist in cache.
     2381 *
     2382 * @since 4.4.0
     2383 * @access private
     2384 *
     2385 * @see update_comment_cache()
     2386 *
     2387 * @global wpdb $wpdb
     2388 *
     2389 * @param array $comment_ids       Array of comment IDs.
     2390 * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
     2391 */
     2392function _prime_comment_caches( $comment_ids, $update_meta_cache = true ) {
     2393    global $wpdb;
     2394
     2395    $non_cached_ids = _get_non_cached_ids( $comment_ids, 'comment' );
     2396    if ( !empty( $non_cached_ids ) ) {
     2397        $fresh_comments = $wpdb->get_results( sprintf( "SELECT $wpdb->comments.* FROM $wpdb->comments WHERE comment_ID IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
     2398
     2399        update_comment_cache( $fresh_comments, $update_meta_cache );
     2400    }
     2401}
     2402
     2403/**
    23802404 * Lazy load comment meta when inside of a `WP_Query` loop.
    23812405 *
  • trunk/tests/phpunit/tests/comment/metaCache.php

    r34270 r34310  
    1717            update_comment_meta( $cid, 'foo', 'bar' );
    1818        }
     19
     20        // Clear comment cache, just in case.
     21        clean_comment_cache( $comment_ids );
    1922
    2023        $q = new WP_Comment_Query( array(
     
    4245            update_comment_meta( $cid, 'foo', 'bar' );
    4346        }
     47
     48        // Clear comment cache, just in case.
     49        clean_comment_cache( $comment_ids );
    4450
    4551        $q = new WP_Comment_Query( array(
  • trunk/tests/phpunit/tests/comment/query.php

    r34212 r34310  
    16681668        $q1->query( array(
    16691669            'post_id' => $p,
     1670            'fields' => 'ids',
    16701671        ) );
    16711672
     
    16751676        $q2->query( array(
    16761677            'post_id' => $p,
     1678            'fields' => 'ids',
    16771679            'foo' => 'bar',
    16781680        ) );
Note: See TracChangeset for help on using the changeset viewer.