[wp-trac] [WordPress Trac] #10964: Improving query_posts performance

WordPress Trac wp-trac at lists.automattic.com
Sun May 1 13:53:27 UTC 2011


#10964: Improving query_posts performance
-------------------------------------+-----------------------------
 Reporter:  buch0090                 |       Owner:
     Type:  enhancement              |      Status:  new
 Priority:  normal                   |   Milestone:  Future Release
Component:  Performance              |     Version:  2.8.4
 Severity:  normal                   |  Resolution:
 Keywords:  has-patch needs-testing  |
-------------------------------------+-----------------------------
Changes (by mwidmann):

 * cc: martin.widmann@… (added)


Comment:

 @scribu: I wanted to give some feedback on the patch you submitted. I
 tried it out as we are currently facing some very strange issues related
 to the {{{SQL_CALC_FOUND_ROWS}}} which caused high load on the servers.

 The problem with the patch is that {{{count(*)}}} and {{{group by}}} when
 used together can create more than one rows of result, making the returned
 number of rows incorrect. In that case you'd have to count the rows
 returned.

 Because there's no easy way for me to fix this in core I created a couple
 of filters to add to a mu-plugin:
 {{{
 add_filter( 'posts_clauses', 'dh_store_last_post_clauses', 10, 2 );
 add_filter( 'query', 'dh_patch_10964', 1 );
 function dh_store_last_post_clauses( $clauses, $wp_query ) {
         global $last_post_clauses;
         $last_post_clauses = $clauses;
         return $clauses;
 }

 function dh_patch_10964( $query ) {
         if ( strpos( $query, 'SQL_CALC_FOUND_ROWS' ) ) {
                 add_filter( 'found_posts_query', 'dh_patch_10964_phase2',
 10, 2 );
                 $query = str_replace( 'SQL_CALC_FOUND_ROWS', '', $query );
         }
         return $query;
 }

 function dh_patch_10964_phase2( $query, $wp_query ) {
         global $wpdb, $last_post_clauses;
         remove_filter( 'found_posts_query', __FUNCTION__ );

         if ( is_array( $last_post_clauses ) ) {
                 $where = '';
                 $groupby = '';
                 $orderby = '';
                 $join = '';

                 $pieces = array( 'where', 'groupby', 'join', 'orderby',
 'distinct', 'fields', 'limits' );
                 foreach ( $pieces as $piece )
                         $$piece = isset( $last_post_clauses[ $piece ] ) ?
 $last_post_clauses[ $piece ] : '';

                 if ( !empty($groupby) )
                         $groupby = 'GROUP BY ' . $groupby;
                 if ( !empty( $orderby ) )
                         $orderby = 'ORDER BY ' . $orderby;
                 $query = "SELECT count(ID) FROM $wpdb->posts $join WHERE
 1=1 $where $groupby $orderby";

                 if ( !empty($groupby) ) {
                         $counts = $wpdb->get_results( $query, ARRAY_N );
                         $rows = sizeof( $counts );
                         $query = "SELECT $rows cnt";
                 }
         }
         return $query;
 }
 }}}

 It seems a little bit hack-ish to me though.

 Explanation what it does:
  1. I store the last post_clauses to the {{{$last_post_clauses}}} global
 in order to have access to this data in the count statement
  1. I look at each {{{query}}} if it contains the
 {{{SQL_CALC_FOUND_ROWS}}} command and remove it from there after
 registering a filter for {{{found_posts_query}}}
  1. in the {{{found_posts_query}}} filter I check the clauses and create
 the count statement. If there's a groupby I execute the query there and
 return a helper sql statement that just returns the number of items
 instead of counting. This way the normal behavior is tricked and the stuff
 works.

-- 
Ticket URL: <http://core.trac.wordpress.org/ticket/10964#comment:86>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software


More information about the wp-trac mailing list