[wp-trac] [WordPress Trac] #7415: "using filesort" in default install

WordPress Trac wp-trac at lists.automattic.com
Sat Jul 26 22:47:55 GMT 2008


#7415: "using filesort" in default install
--------------------------+-------------------------------------------------
 Reporter:  dbuser123     |       Owner:  anonymous                                     
     Type:  defect        |      Status:  new                                           
 Priority:  normal        |   Milestone:  2.7                                           
Component:  Optimization  |     Version:                                                
 Severity:  normal        |    Keywords:  database, optimization, slow queries, filesort
--------------------------+-------------------------------------------------
 I took the database of a large existing WP blog (10k posts, 30k comments)
 and got it to work with a fresh and clean WP install with the Default
 theme without any plugins.

 There are ridiculously many queries executed: 50. Here are some
 recommendations:

 Almost half of them are like "SELECT `post_parent` FROM wp_posts WHERE ID=
 '...' LIMIT 1", just after a "SELECT * FROM wp_posts WHERE (post_type =
 'page' AND post_status = 'publish') ORDER BY menu_order, post_title ASC".
 A left join would be appropriate. Even if you don't want to join, you
 could cache the post_parent because many posts could have the same parent.


 The slowest query by far (40% of total query time) is this one:
 SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts WHERE 1=1 AND
 wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR
 wp_posts.post_status = 'private') ORDER BY wp_posts.post_date DESC LIMIT
 0, 6
 This query had to sort 3000 rows BY HAND (only if logged in as admin).
 Because of the OR, the post_date part of the index
 (post_type,post_status,post_date,ID) could not be used for sorting. A
 UNION would solve this problem:
 (SELECT wp_posts.* FROM wp_posts WHERE wp_posts.post_type = 'post' AND
 wp_posts.post_status = 'publish' ORDER BY wp_posts.post_date DESC LIMIT 0,
 6)
 UNION
 (SELECT wp_posts.* FROM wp_posts WHERE wp_posts.post_type = 'post' AND
 wp_posts.post_status = 'private' ORDER BY wp_posts.post_date DESC LIMIT 0,
 6)
 ORDER BY post_date DESC LIMIT 0,6

 The second problem with this query is the SQL_CALC_FOUND_ROWS. It makes
 MySQL retrieve all rows, thus causing much disk i/o. It's way faster to do
 a second query that does a count(*) because it can be done by reading the
 index instead of the rows. This made the query 10 times as fast for me.


 Next one: SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE
 post_id IN (9109,9103,9052,9112,9100,9096) ORDER BY post_id, meta_key
 I have no idea why it has to be sorted by meta_key as well, but as the
 table is not indexed on (post_id,meta_key), it causes a manual sort.


 Yet another one: SELECT * FROM wp_posts WHERE (post_type = 'page' AND
 post_status = 'publish') ORDER BY menu_order, post_title ASC
 Has to be ordered manually again because there's no appropriate index.


 I hope somebody will look at the db-optimization because there's still
 lots of room for improvement. To assist you, set SAVEQUERIES to true and
 change the destructor of wp-db.php:


 function __destruct() {
         $ttime = 0;
         foreach($this->queries as $q) $ttime += $q[1];
         echo '<div style="text-align:left; font-family:courier new; font-
 size: 14;">';
         foreach($this->queries as $q) {
                 $i++;
                 echo '[' . $i . '] (' . round(100*$q[1]/$ttime,5) . '% - '
 . round($q[1],5) . 's) ' . htmlspecialchars($q[0]) . '<br />';
         }
         echo '</div>';
         return true;
 }

-- 
Ticket URL: <http://trac.wordpress.org/ticket/7415>
WordPress Trac <http://trac.wordpress.org/>
WordPress blogging software


More information about the wp-trac mailing list