简体   繁体   中英

Optimizing MySQL LEFT JOIN query

My goal is to select articles where the primary_category_id ( articles table) or any of the secondary categories ( articles_secondary_categories join table) are a given value. In this example query, category 1. I tried using other types of joins but the caveat here is that an article might not have any secondary categories.

SELECT DISTINCT articles.* 
FROM articles
LEFT JOIN articles_secondary_categories AS categories 
    ON categories.article_id = articles.id
WHERE 
(
    primary_category_id = 1
    OR
    categories.category_id = 1
)
    AND articles.state = "published"
    AND edition_id = 1

ORDER BY publish_at DESC
LIMIT 10;

Any help optimizing this or alternatives are welcome. In a DB with 4k articles and 7k articles_secondary_categories (not categories) it takes 5 seconds to run this query.

You can reverse the query on the secondary categories:

(SELECT articles.* 
FROM articles
WHERE primary_category_id = 1)
UNION DISTINCT
(SELECT articles.*
FROM articles_secondary_categories AS categories 
JOIN articles ON (categories.article_id = articles.id)
WHERE categories.category_id = 1
GROUP BY articles_id)
ORDER BY publish_at DESC
LIMIT 10;

It should give you a decent speed boost - just make sure you index categories.articles_id

Avoid using OR in your where clause. Optimizers usually don't use indexes with OR predicates.

Try moving the categories.category_id = 1 into the join condition:

SELECT articles.* 
FROM articles
LEFT JOIN articles_secondary_categories AS categories 
    ON categories.article_id = articles.id and categories.category_id = 1
WHERE 1 in (ifnull(categories.category_id, primary_category_id), primary_category_id)
AND articles.state = "published"
AND edition_id = 1
ORDER BY publish_at DESC
LIMIT 10;

The key to this query is 1 in (ifnull(categories.category_id, primary_category_id), primary_category_id) , which says "if we got a join to categories, use that in the list, otherwise use the primary_category_id, and in all cases use the primary_category_id.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM