Optimising mysql query – many inner joins

I’m trying to optimise the following query in wordpress, as it takes nearly a minute and a half to return a result. The table relationships are expressed in the following diagram:

enter image description here

SELECT SQL_CALC_FOUND_ROWS wp_posts . *
    FROM wp_posts
       INNER JOIN wp_term_relationships 
        ON (wp_posts.ID = wp_term_relationships.object_id)
       INNER JOIN wp_term_relationships AS tt1 
        ON (wp_posts.ID = tt1.object_id)
       INNER JOIN wp_term_relationships AS tt2 
        ON (wp_posts.ID = tt2.object_id)
       INNER JOIN wp_term_relationships AS tt3 
        ON (wp_posts.ID = tt3.object_id)
       INNER JOIN wp_term_relationships AS tt4 
        ON (wp_posts.ID = tt4.object_id)
    WHERE 1 = 1
        AND (
            wp_term_relationships.term_taxonomy_id IN (25) 
            OR tt1.term_taxonomy_id IN (26) 
            OR tt2.term_taxonomy_id IN (16) 
            OR tt3.term_taxonomy_id IN (17) 
            OR tt4.term_taxonomy_id IN (18)
        ) 
        AND wp_posts.post_type IN ('product') 
        AND (wp_posts.post_status = 'publish')
    GROUP BY wp_posts.ID
    ORDER BY wp_posts.post_title ASC
    LIMIT 0 , 15

Related posts

Leave a Reply

3 comments

  1. I don’t understand the point of all the inner joins on the wp_term_relationships table when all it appears you’re doing is looking for a series of values. Wouldn’t the following perform the same and execute much faster?

    SELECT SQL_CALC_FOUND_ROWS wp_posts . *
        FROM wp_posts
           INNER JOIN wp_term_relationships 
            ON (wp_posts.ID = wp_term_relationships.object_id)
        WHERE wp_term_relationships.term_taxonomy_id IN (25, 26, 16, 17, 18) 
            AND wp_posts.post_type = 'product' 
            AND wp_posts.post_status = 'publish'
        GROUP BY wp_posts.ID
        ORDER BY wp_posts.post_title ASC
        LIMIT 0 , 15
    
  2. Try this. I think this will be faster.

    SELECT SQL_CALC_FOUND_ROWS wp_posts . *
    FROM wp_posts,
         wp_term_relationships 
    WHERE wp_posts.ID = wp_term_relationships.object_id
    AND wp_term_relationships.term_taxonomy_id IN (25,26,16,17,18)
    AND wp_posts.post_type = 'product' 
    AND wp_posts.post_status = 'publish'
    GROUP BY wp_posts.ID
    ORDER BY wp_posts.post_title ASC
    LIMIT 0 , 15
    

    You do not need so many INNER JOINS.

  3. If the idea behind the multiple joins was to retrieve the posts with a corresponding term_taxonomy_id of 25 and also 26 and also 17,… (meaning ALL of the terms as opposed to ANY of them), you can reuse KayakJim’s answer with only one JOIN and add an HAVING clause, keeping only the rows that matched with all of the 5 terms.

    Here would be the modified query:

    SELECT SQL_CALC_FOUND_ROWS wp_posts . *
        FROM wp_posts
           INNER JOIN wp_term_relationships 
            ON (wp_posts.ID = wp_term_relationships.object_id)
        WHERE wp_term_relationships.term_taxonomy_id IN (25, 26, 16, 17, 18) 
            AND wp_posts.post_type = 'product' 
            AND wp_posts.post_status = 'publish'
        GROUP BY wp_posts.ID
        HAVING count(*)=5
        ORDER BY wp_posts.post_title ASC
        LIMIT 0 , 15