[wp-trac] [WordPress Trac] #40434: Optimize SQL in Admin - In the Post/CPT List `wp-admin/edit.php` > the function get_posts()

WordPress Trac noreply at wordpress.org
Thu Apr 13 09:00:57 UTC 2017


#40434: Optimize SQL in Admin - In the Post/CPT List `wp-admin/edit.php` > the
function get_posts()
----------------------------+-----------------------------
 Reporter:  lriaudel        |      Owner:
     Type:  enhancement     |     Status:  new
 Priority:  normal          |  Milestone:  Awaiting Review
Component:  Administration  |    Version:  4.7.3
 Severity:  normal          |   Keywords:
  Focuses:  performance     |
----------------------------+-----------------------------
 When we list a post, a page or a custom-post-type the default query is
 {{{
 SELECT SQL_CALC_FOUND_ROWS en_posts.ID
 FROM en_posts
 WHERE 1=1
 AND en_posts.post_type = 'post'
 AND (en_posts.post_status = 'publish'
 OR en_posts.post_status = 'moderation'
 OR en_posts.post_status = 'refusal'
 OR en_posts.post_status = 'future'
 OR en_posts.post_status = 'draft'
 OR en_posts.post_status = 'pending'
 OR en_posts.post_status = 'private')
 ORDER BY en_posts.post_date DESC
 LIMIT 0, 20
 }}}


 This query cause slow queries. The operation `OR` is not appropriate and
 not optimize.
 It is better to use the operation `IN`.

 I propose to change lines in the `clasw-wp-query.php` line 2348:

 Today :
 {{{#!php
 <?php
                 } elseif ( !$this->is_singular ) {
                         $where .= " AND ({$wpdb->posts}.post_status =
 'publish'";

                         // Add public states.
                         $public_states = get_post_stati( array('public' =>
 true) );
                         foreach ( (array) $public_states as $state ) {
                                 if ( 'publish' == $state ) // Publish is
 hard-coded above.
                                         continue;
                                 $where .= " OR {$wpdb->posts}.post_status
 = '$state'";
                         }

                         if ( $this->is_admin ) {
                                 // Add protected states that should show
 in the admin all list.
                                 $admin_all_states = get_post_stati(
 array('protected' => true, 'show_in_admin_all_list' => true) );
                                 foreach ( (array) $admin_all_states as
 $state ) {
                                         $where .= " OR
 {$wpdb->posts}.post_status = '$state'";
                                 }
                         }

                         if ( is_user_logged_in() ) {
                                 // Add private states that are limited to
 viewing by the author of a post or someone who has caps to read private
 states.
                                 $private_states = get_post_stati(
 array('private' => true) );
                                 foreach ( (array) $private_states as
 $state ) {
                                         $where .= current_user_can(
 $read_private_cap ) ? " OR {$wpdb->posts}.post_status = '$state'" : " OR
 {$wpdb->posts}.post_author = $user_id AND {$wpdb->posts}.post_status =
 '$state'";
                                 }
                         }

                         $where .= ')';
                 }
 }}}

 The proposition :
 {{{#!php
 <?php
                 } elseif ( !$this->is_singular ) {
                         $where_status[] = 'publish';

                         // Add public states.
                         $public_states = get_post_stati( array('public' =>
 true) );
                         foreach ( (array) $public_states as $state ) {
                                 if ( 'publish' == $state ) // Publish is
 hard-coded above.
                                         continue;
                                 $where_status[] = $state;
                         }

                         if ( $this->is_admin ) {
                                 // Add protected states that should show
 in the admin all list.
                                 $admin_all_states = get_post_stati(
 array('protected' => true, 'show_in_admin_all_list' => true) );
                                 foreach ( (array) $admin_all_states as
 $state ) {
                                         $where_status[] = $state;
                                 }
                         }

                         if ( is_user_logged_in() ) {
                                 // Add private states that are limited to
 viewing by the author of a post or someone who has caps to read private
 states.
                                 $private_states = get_post_stati(
 array('private' => true) );
                                 foreach ( (array) $private_states as
 $state ) {
                                         $where_status[] = $state;
                                         $where_post_author =
 current_user_can( $read_private_cap ) ? "" : " OR
 {$wpdb->posts}.post_author = $user_id";
                                 }
                         }
                         $where .= " AND ( {$wpdb->posts}.post_status IN
 ('" . implode("','",$where_status) . "')";
                         $where .= $where_post_author;
                         $where .= ')';
                 }
 }}}

 And the result is better :
 {{{
 SELECT SQL_CALC_FOUND_ROWS en_posts.ID
 FROM en_posts
 WHERE 1=1
 AND en_posts.post_type = 'post'
 AND ( en_posts.post_status IN
 ('publish','moderation','refusal','future','draft','pending','private'))
 ORDER BY en_posts.post_date DESC
 LIMIT 0, 20
 }}}

 It would be interesting to do the same work on other parts of get_posts
 where the `OR` is used.

--
Ticket URL: <https://core.trac.wordpress.org/ticket/40434>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list