WordPress.org

Make WordPress Core


Ignore:
Timestamp:
10/15/2014 04:39:19 PM (7 years ago)
Author:
boonebgorges
Message:

Avoid redundant table joins in WP_Tax_Query.

IN clauses that are connected by OR require only a single table join. To avoid
extraneous joins, keep track of generated table aliases, and let sibling
clauses piggy-back on those aliases when possible.

Introduces WP_Tax_Query::sanitize_relation() to reduce some repeated code.

Adds unit tests to verify the JOIN consolidation, and integration tests for
cases where JOINS are being combined.

Props boonebgorges, otto42, jakub.tyrcha.
Fixes #18105.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/term/query.php

    r29805 r29902  
    219219        $this->assertTrue( is_wp_error( $tq->queries[0] ) );
    220220    }
     221
     222    /**
     223     * @ticket 18105
     224     */
     225    public function test_get_sql_relation_or_operator_in() {
     226        register_taxonomy( 'wptests_tax', 'post' );
     227
     228        $t1 = $this->factory->term->create( array(
     229            'taxonomy' => 'wptests_tax',
     230        ) );
     231        $t2 = $this->factory->term->create( array(
     232            'taxonomy' => 'wptests_tax',
     233        ) );
     234        $t3 = $this->factory->term->create( array(
     235            'taxonomy' => 'wptests_tax',
     236        ) );
     237
     238        $tq = new WP_Tax_Query( array(
     239            'relation' => 'OR',
     240            array(
     241                'taxonomy' => 'wptests_tax',
     242                'field' => 'term_id',
     243                'terms' => $t1,
     244            ),
     245            array(
     246                'taxonomy' => 'wptests_tax',
     247                'field' => 'term_id',
     248                'terms' => $t2,
     249            ),
     250            array(
     251                'taxonomy' => 'wptests_tax',
     252                'field' => 'term_id',
     253                'terms' => $t3,
     254            ),
     255        ) );
     256
     257        global $wpdb;
     258        $sql = $tq->get_sql( $wpdb->posts, 'ID' );
     259
     260        // Only one JOIN is required with OR + IN.
     261        $this->assertSame( 1, substr_count( $sql['join'], 'JOIN' ) );
     262
     263        _unregister_taxonomy( 'wptests_tax' );
     264    }
     265
     266    /**
     267     * @ticket 18105
     268     */
     269    public function test_get_sql_relation_and_operator_in() {
     270        register_taxonomy( 'wptests_tax', 'post' );
     271
     272        $t1 = $this->factory->term->create( array(
     273            'taxonomy' => 'wptests_tax',
     274        ) );
     275        $t2 = $this->factory->term->create( array(
     276            'taxonomy' => 'wptests_tax',
     277        ) );
     278        $t3 = $this->factory->term->create( array(
     279            'taxonomy' => 'wptests_tax',
     280        ) );
     281
     282        $tq = new WP_Tax_Query( array(
     283            'relation' => 'AND',
     284            array(
     285                'taxonomy' => 'wptests_tax',
     286                'field' => 'term_id',
     287                'terms' => $t1,
     288            ),
     289            array(
     290                'taxonomy' => 'wptests_tax',
     291                'field' => 'term_id',
     292                'terms' => $t2,
     293            ),
     294            array(
     295                'taxonomy' => 'wptests_tax',
     296                'field' => 'term_id',
     297                'terms' => $t3,
     298            ),
     299        ) );
     300
     301        global $wpdb;
     302        $sql = $tq->get_sql( $wpdb->posts, 'ID' );
     303
     304        $this->assertSame( 3, substr_count( $sql['join'], 'JOIN' ) );
     305
     306        _unregister_taxonomy( 'wptests_tax' );
     307    }
     308
     309    /**
     310     * @ticket 18105
     311     */
     312    public function test_get_sql_nested_relation_or_operator_in() {
     313        register_taxonomy( 'wptests_tax', 'post' );
     314
     315        $t1 = $this->factory->term->create( array(
     316            'taxonomy' => 'wptests_tax',
     317        ) );
     318        $t2 = $this->factory->term->create( array(
     319            'taxonomy' => 'wptests_tax',
     320        ) );
     321        $t3 = $this->factory->term->create( array(
     322            'taxonomy' => 'wptests_tax',
     323        ) );
     324
     325        $tq = new WP_Tax_Query( array(
     326            'relation' => 'OR',
     327            array(
     328                'taxonomy' => 'wptests_tax',
     329                'field' => 'term_id',
     330                'terms' => $t1,
     331            ),
     332            array(
     333                'relation' => 'OR',
     334                array(
     335                    'taxonomy' => 'wptests_tax',
     336                    'field' => 'term_id',
     337                    'terms' => $t2,
     338                ),
     339                array(
     340                    'taxonomy' => 'wptests_tax',
     341                    'field' => 'term_id',
     342                    'terms' => $t3,
     343                ),
     344            ),
     345        ) );
     346
     347        global $wpdb;
     348        $sql = $tq->get_sql( $wpdb->posts, 'ID' );
     349
     350        $this->assertSame( 2, substr_count( $sql['join'], 'JOIN' ) );
     351
     352        _unregister_taxonomy( 'wptests_tax' );
     353    }
     354
    221355}
Note: See TracChangeset for help on using the changeset viewer.