[wp-trac] [WordPress Trac] #19729: WP_Meta_Query is inefficient when only specifying keys in "OR" query
WordPress Trac
wp-trac at lists.automattic.com
Tue Jan 3 21:46:54 UTC 2012
#19729: WP_Meta_Query is inefficient when only specifying keys in "OR" query
-------------------------+-----------------------------
Reporter: joehoyle | Owner:
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Query | Version: 3.3
Severity: normal | Keywords:
-------------------------+-----------------------------
Suppose I have a WP_Query like so:
{{{
$query = new WP_Query( array( 'meta_query' => array(
array( 'key' => 'foo' ),
array( 'key' => 'bar', 'value' => 'val2' ),
array( 'key' => 'baz' ),
array( 'key' => 'froo' ) 'relation' => 'OR' ) ) );
}}}
Currently, `WP_Meta_Query` will JOIN 4 copies of postmeta and use one JOIN
per key - however, when using a relation of OR, it's not necessary to use
more than one meta JOIN for the key-only queries.
The attached patch will pull out all the "key only" queries and use a
single JOIN for them, leaving the remaining quires in-tact as they were
before.
This can only be done with an OR query, of course.
Below is the SQL query before the patch:
{{{
SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts INNER JOIN
wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
INNER JOIN wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id) WHERE 1=1
AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR
wp_posts.post_status = 'private') AND (wp_postmeta.meta_key = 'foo'
OR (mt1.meta_key = 'bar' AND CAST(mt1.meta_value AS CHAR) = 'val2')
OR mt2.meta_key = 'baz'
OR mt3.meta_key = 'froo' ) GROUP BY wp_posts.ID ORDER BY
wp_posts.post_date DESC LIMIT 0, 10
}}}
The same after the patch:
{{{
SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts INNER JOIN
wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) WHERE 1=1
AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR
wp_posts.post_status = 'private') AND (wp_postmeta.meta_key = 'foo'
OR wp_postmeta.meta_key = 'baz'
OR wp_postmeta.meta_key = 'froo'
OR (mt1.meta_key = 'bar' AND CAST(mt1.meta_value AS CHAR) = 'val2') )
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10
}}}
I ran this on a large site (>100k posts), so not sure if the performance
gains will be so drastic for smaller sites. Before the patch, with 3 JOINS
took around 43seconds. After the patch with 1 Join, 5.2ms. Not sure why
the hug difference, presumably multiple JOINS was killing it somehow.
--
Ticket URL: <http://core.trac.wordpress.org/ticket/19729>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software
More information about the wp-trac
mailing list