Make WordPress Core

Changeset 52970


Ignore:
Timestamp:
03/21/2022 03:53:33 AM (3 years ago)
Author:
peterwilsoncc
Message:

Taxonomy: Increase cache hits in WP_Term_Query.

Increase the number of cache hits in WP_Term_Query by normalizing data included in the cache key.

Arguments that do not affect the SQL query, eg update_term_meta_cache, are removed from cache key generation. Arguments that are accepted in multiple formats, eg a string and an array, are normalized for both the cache key and the SQL query.

Props spacedmonkey.
Fixes #55352.

Location:
trunk
Files:
2 edited

Legend:

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

    r52836 r52970  
    527527        }
    528528
    529         if (
    530             ( ! empty( $args['name'] ) ) ||
    531             ( is_string( $args['name'] ) && 0 !== strlen( $args['name'] ) )
    532         ) {
    533             $names = (array) $args['name'];
     529        $args['name'] = is_string( $args['name'] ) && 0 === strlen( $args['name'] ) ? array() : (array) $args['name'];
     530        if ( ! empty( $args['name'] ) ) {
     531            $names = $args['name'];
    534532            foreach ( $names as &$_name ) {
    535533                // `sanitize_term_field()` returns slashed data.
     
    540538        }
    541539
    542         if (
    543             ( ! empty( $args['slug'] ) ) ||
    544             ( is_string( $args['slug'] ) && 0 !== strlen( $args['slug'] ) )
    545         ) {
    546             if ( is_array( $args['slug'] ) ) {
    547                 $slug                               = array_map( 'sanitize_title', $args['slug'] );
    548                 $this->sql_clauses['where']['slug'] = "t.slug IN ('" . implode( "', '", $slug ) . "')";
    549             } else {
    550                 $slug                               = sanitize_title( $args['slug'] );
    551                 $this->sql_clauses['where']['slug'] = "t.slug = '$slug'";
    552             }
    553         }
    554 
     540        $args['slug'] = is_string( $args['slug'] ) && 0 === strlen( $args['slug'] ) ? array() : array_map( 'sanitize_title', (array) $args['slug'] );
     541        if ( ! empty( $args['slug'] ) ) {
     542            $slug = implode( "', '", $args['slug'] );
     543
     544            $this->sql_clauses['where']['slug'] = "t.slug IN ('" . $slug . "')";
     545        }
     546
     547        $args['term_taxonomy_id'] = is_string( $args['term_taxonomy_id'] ) && 0 === strlen( $args['term_taxonomy_id'] ) ? array() : array_map( 'intval', (array) $args['term_taxonomy_id'] );
    555548        if ( ! empty( $args['term_taxonomy_id'] ) ) {
    556             if ( is_array( $args['term_taxonomy_id'] ) ) {
    557                 $tt_ids = implode( ',', array_map( 'intval', $args['term_taxonomy_id'] ) );
    558                 $this->sql_clauses['where']['term_taxonomy_id'] = "tt.term_taxonomy_id IN ({$tt_ids})";
    559             } else {
    560                 $this->sql_clauses['where']['term_taxonomy_id'] = $wpdb->prepare( 'tt.term_taxonomy_id = %d', $args['term_taxonomy_id'] );
    561             }
     549            $tt_ids = implode( ',', $args['term_taxonomy_id'] );
     550
     551            $this->sql_clauses['where']['term_taxonomy_id'] = "tt.term_taxonomy_id IN ({$tt_ids})";
    562552        }
    563553
     
    570560        }
    571561
     562        $args['object_ids'] = is_string( $args['object_ids'] ) && 0 === strlen( $args['object_ids'] ) ? array() : array_map( 'intval', (array) $args['object_ids'] );
    572563        if ( ! empty( $args['object_ids'] ) ) {
    573             $object_ids = $args['object_ids'];
    574             if ( ! is_array( $object_ids ) ) {
    575                 $object_ids = array( $object_ids );
    576             }
    577 
    578             $object_ids                               = implode( ', ', array_map( 'intval', $object_ids ) );
     564            $object_ids = implode( ', ', $args['object_ids'] );
     565
    579566            $this->sql_clauses['where']['object_ids'] = "tr.object_id IN ($object_ids)";
    580567        }
     
    729716
    730717        // $args can be anything. Only use the args defined in defaults to compute the key.
    731         $key          = md5( serialize( wp_array_slice_assoc( $args, array_keys( $this->query_var_defaults ) ) ) . serialize( $taxonomies ) . $this->request );
     718        $cache_args = wp_array_slice_assoc( $args, array_keys( $this->query_var_defaults ) );
     719        unset( $cache_args['pad_counts'], $cache_args['update_term_meta_cache'] );
     720        if ( 'count' !== $_fields && 'all_with_object_id' !== $_fields ) {
     721            $cache_args['fields'] = 'all';
     722        }
     723        $key          = md5( serialize( $cache_args ) . serialize( $taxonomies ) . $this->request );
    732724        $last_changed = wp_cache_get_last_changed( 'terms' );
    733725        $cache_key    = "get_terms:$key:$last_changed";
  • trunk/tests/phpunit/tests/term/getTerms.php

    r52836 r52970  
    55 */
    66class Tests_Term_getTerms extends WP_UnitTestCase {
     7
     8    protected static $taxonomy = 'wptests_tax_3';
     9
    710    public function set_up() {
    811        parent::set_up();
    912
     13        register_taxonomy( self::$taxonomy, 'post', array( 'hierarchical' => true ) );
     14
    1015        _clean_term_filters();
    1116        wp_cache_delete( 'last_changed', 'terms' );
     17    }
     18
     19    public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
     20        register_taxonomy( self::$taxonomy, 'page', array( 'hierarchical' => true ) );
     21        $term_id1 = $factory->term->create(
     22            array(
     23                'name'     => 'Foo',
     24                'slug'     => 'Foo',
     25                'taxonomy' => self::$taxonomy,
     26            )
     27        );
     28        $term_id2 = $factory->term->create(
     29            array(
     30                'name'     => 'Bar',
     31                'slug'     => 'bar',
     32                'taxonomy' => self::$taxonomy,
     33            )
     34        );
     35        $posts    = $factory->post->create_many( 3, array( 'post_type' => 'page' ) );
     36        foreach ( $posts as $i => $post ) {
     37            wp_set_object_terms( $post, array( $term_id1, $term_id2 ), self::$taxonomy );
     38        }
    1239    }
    1340
     
    29893016    }
    29903017
     3018
     3019    /**
     3020     * @ticket 55352
     3021     */
     3022    public function test_cache_key_generation_cache_domain() {
     3023        $args_1        = array(
     3024            'taxonomy' => self::$taxonomy,
     3025            'fields'   => 'ids',
     3026        );
     3027        $args_2        = array_merge( $args_1, array( 'cache_domain' => microtime() ) );
     3028        $query1        = get_terms( $args_1 );
     3029        $num_queries_1 = get_num_queries();
     3030        $query2        = get_terms( $args_2 );
     3031        $this->assertNotSame( $num_queries_1, get_num_queries() );
     3032        $this->assertSameSets( $query1, $query2 );
     3033    }
     3034
     3035    /**
     3036     * @ticket 55352
     3037     */
     3038    public function test_cache_key_generation_all_with_object_id() {
     3039        $args_1        = array(
     3040            'taxonomy' => self::$taxonomy,
     3041            'fields'   => 'ids',
     3042        );
     3043        $args_2        = array_merge( $args_1, array( 'fields' => 'all_with_object_id' ) );
     3044        $query1        = get_terms( $args_1 );
     3045        $num_queries_1 = get_num_queries();
     3046        $query2        = get_terms( $args_2 );
     3047        $this->assertNotSame( $num_queries_1, get_num_queries() );
     3048        $this->assertSameSets( $query1, wp_list_pluck( $query2, 'term_id' ) );
     3049    }
     3050
     3051
     3052    /**
     3053     * @ticket 55352
     3054     *
     3055     * @dataProvider data_same_term_args
     3056     */
     3057    public function test_cache_key_generation( $args_1, $args_2 ) {
     3058        $query1        = get_terms( $args_1 );
     3059        $num_queries_1 = get_num_queries();
     3060        $query2        = get_terms( $args_2 );
     3061        $this->assertSame( $num_queries_1, get_num_queries() );
     3062        $this->assertSame( count( $query1 ), count( $query2 ) );
     3063    }
     3064
     3065    /**
     3066     * Data provider.
     3067     *
     3068     * @return array
     3069     */
     3070    public function data_same_term_args() {
     3071        return array(
     3072            'all fields vs ids'                        => array(
     3073                array(
     3074                    'taxonomy' => self::$taxonomy,
     3075                    'fields'   => 'ids',
     3076                ),
     3077                array(
     3078                    'taxonomy' => self::$taxonomy,
     3079                    'fields'   => 'all',
     3080                ),
     3081            ),
     3082            'array taxonomy vs string taxonomy'        => array(
     3083                array(
     3084                    'taxonomy' => self::$taxonomy,
     3085                    'fields'   => 'all',
     3086                ),
     3087                array(
     3088                    'taxonomy' => array( self::$taxonomy ),
     3089                    'fields'   => 'all',
     3090                ),
     3091            ),
     3092            'slug fields vs names fields'              => array(
     3093                array(
     3094                    'taxonomy' => self::$taxonomy,
     3095                    'fields'   => 'names',
     3096                ),
     3097                array(
     3098                    'taxonomy' => self::$taxonomy,
     3099                    'fields'   => 'slugs',
     3100                ),
     3101            ),
     3102            'meta cache off, pad count on  vs meta cache on, pad count off' => array(
     3103                array(
     3104                    'taxonomy'               => self::$taxonomy,
     3105                    'pad_counts'             => true,
     3106                    'update_term_meta_cache' => false,
     3107                ),
     3108                array(
     3109                    'taxonomy' => self::$taxonomy,
     3110                    'fields'   => 'ids',
     3111                ),
     3112            ),
     3113            'array slug vs string slug'                => array(
     3114                array(
     3115                    'taxonomy' => self::$taxonomy,
     3116                    'fields'   => 'all',
     3117                    'slug'     => '',
     3118                ),
     3119                array(
     3120                    'taxonomy' => self::$taxonomy,
     3121                    'fields'   => 'all',
     3122                    'slug'     => array(),
     3123                ),
     3124            ),
     3125            'array object_ids vs string object_ids'    => array(
     3126                array(
     3127                    'taxonomy'   => self::$taxonomy,
     3128                    'fields'     => 'all',
     3129                    'object_ids' => '',
     3130                ),
     3131                array(
     3132                    'taxonomy'   => self::$taxonomy,
     3133                    'fields'     => 'all',
     3134                    'object_ids' => array(),
     3135                ),
     3136            ),
     3137            'array term_taxonomy_id vs string term_taxonomy_id' => array(
     3138                array(
     3139                    'taxonomy'         => self::$taxonomy,
     3140                    'fields'           => 'ids',
     3141                    'term_taxonomy_id' => '',
     3142                ),
     3143                array(
     3144                    'taxonomy'         => self::$taxonomy,
     3145                    'fields'           => 'all',
     3146                    'term_taxonomy_id' => array(),
     3147                ),
     3148            ),
     3149            'array 1 slug vs string slug'              => array(
     3150                array(
     3151                    'taxonomy' => self::$taxonomy,
     3152                    'fields'   => 'ids',
     3153                    'slug'     => 'bar',
     3154                ),
     3155                array(
     3156                    'taxonomy' => self::$taxonomy,
     3157                    'fields'   => 'all',
     3158                    'slug'     => array( 'bar' ),
     3159                ),
     3160            ),
     3161            'int object_ids vs array object_ids'       => array(
     3162                array(
     3163                    'taxonomy'   => self::$taxonomy,
     3164                    'fields'     => 'ids',
     3165                    'object_ids' => 1,
     3166                ),
     3167                array(
     3168                    'taxonomy'   => self::$taxonomy,
     3169                    'fields'     => 'all',
     3170                    'object_ids' => array( 1 ),
     3171                ),
     3172            ),
     3173            'string object_ids vs array object_ids'    => array(
     3174                array(
     3175                    'taxonomy'   => self::$taxonomy,
     3176                    'fields'     => 'ids',
     3177                    'object_ids' => '1',
     3178                ),
     3179                array(
     3180                    'taxonomy'   => self::$taxonomy,
     3181                    'fields'     => 'all',
     3182                    'object_ids' => array( 1 ),
     3183                ),
     3184            ),
     3185            'int term_taxonomy_id vs array term_taxonomy_id and fields different' => array(
     3186                array(
     3187                    'taxonomy'         => self::$taxonomy,
     3188                    'fields'           => 'ids',
     3189                    'term_taxonomy_id' => 1,
     3190                ),
     3191                array(
     3192                    'taxonomy'         => self::$taxonomy,
     3193                    'fields'           => 'all',
     3194                    'term_taxonomy_id' => array( 1 ),
     3195                ),
     3196            ),
     3197            'same arguments in a different order'      => array(
     3198                array(
     3199                    'fields'           => 'ids',
     3200                    'taxonomy'         => self::$taxonomy,
     3201                    'term_taxonomy_id' => 1,
     3202                ),
     3203                array(
     3204                    'term_taxonomy_id' => 1,
     3205                    'taxonomy'         => self::$taxonomy,
     3206                    'fields'           => 'ids',
     3207                ),
     3208            ),
     3209            'invalid arguments discarded in cache key' => array(
     3210                array(
     3211                    'fields'           => 'ids',
     3212                    'taxonomy'         => self::$taxonomy,
     3213                    'term_taxonomy_id' => 1,
     3214                    'ticket_number'    => '55352',
     3215                ),
     3216                array(
     3217                    'fields'           => 'all',
     3218                    'taxonomy'         => self::$taxonomy,
     3219                    'term_taxonomy_id' => array( 1 ),
     3220                    'focus'            => 'performance',
     3221                ),
     3222            ),
     3223        );
     3224    }
     3225
    29913226    /**
    29923227     * @ticket 21760
Note: See TracChangeset for help on using the changeset viewer.