Make WordPress Core

Opened 14 years ago

Closed 14 years ago

Last modified 14 years ago

#17288 closed enhancement (duplicate)

slow query in taxonomy.php

Reported by: fudj's profile fudj Owned by:
Milestone: Priority: normal
Severity: normal Version: 3.1
Component: Taxonomy Keywords: needs-testing
Focuses: Cc:

Description

platform: ubuntu 10.04
wordpress: 3.1.1
mysql: 5.1.43

mySQL 5.1.43 (which is what I am running) optimises the query incorrectly, which is particularly slow on my site that has 2000+ posts (40000+ rows in wp_posts)

OLD QUERY (took 180sec+ to execute)

SELECT SQL_CALC_FOUND_ROWS  wp_posts.* FROM wp_posts  WHERE 1=1  AND ( wp_posts.ID IN (
    					SELECT object_id
    					FROM wp_term_relationships
    					WHERE term_taxonomy_id IN (4594,4600)
    					GROUP BY object_id HAVING COUNT(object_id) = 2
    				) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;

NEW QUERY (<1sec)

SELECT SQL_CALC_FOUND_ROWS  wp_posts.* FROM wp_posts  WHERE 1=1  AND EXISTS (
                       SELECT 1
                       FROM wp_term_relationships
                       WHERE term_taxonomy_id IN (4594,4600)
    AND object_id = wp_posts.ID
                       GROUP BY object_id HAVING COUNT(object_id) = 2
                   )  AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;

the way to get around it is to change the sub query in taxonomy.php:

LINE 697-702 - replace with:

    $where[] = "EXISTS (
    	SELECT 1
    	FROM $wpdb->term_relationships
    	WHERE term_taxonomy_id IN ($terms)
    	AND object_id = $primary_table.$primary_id_column
    	GROUP BY object_id HAVING COUNT(object_id) = $num_terms
    )";

it forces the DB to evaluate inside first.
I'd be interested if this works on other people's servers.
There is a faster version using an inner join, but it changes the query structure so requires a bit more code editing that I haven't got around to looking at:

POSSIBLE NEWER BETTER QUERY (requiring more code editing)

    SELECT SQL_CALC_FOUND_ROWS  wp_posts.*
    FROM wp_posts
            INNER JOIN (
                    SELECT object_id
            FROM wp_term_relationships
            WHERE term_taxonomy_id IN (4594,4600)
            GROUP BY object_id
                    HAVING COUNT(object_id) = 2
            ) as term ON term.object_id = wp_posts.ID
    WHERE 1=1
            AND wp_posts.post_type = 'post'
            AND (wp_posts.post_status = 'publish')
    GROUP BY wp_posts.ID
    ORDER BY wp_posts.post_date DESC LIMIT 0, 10;

This one gets rid of the looping that occurs in the previous queries

Change History (3)

#2 @fudj
14 years ago

  • Resolution set to duplicate
  • Status changed from new to closed

damn, didn't see that one...

#3 @scribu
14 years ago

  • Milestone Awaiting Review deleted
Note: See TracTickets for help on using tickets.