简体   繁体   English

优化MySQL LEFT JOIN查询

[英]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. 我的目标是选择primary_category_idarticles表)或任何辅助类别( articles_secondary_categories连接表)为给定值的文章。 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. 在此示例查询中,类别1。我尝试使用其他类型的联接,但这里的警告是,文章可能没有任何二级类别。

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. 在与4K一个DB articles和7K articles_secondary_categories (未分类)需要5秒钟,运行此查询。

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 它应该为您带来不错的速度提升-只需确保您为category.articles_id编制索引

Avoid using OR in your where clause. 避免在where子句中使用OR Optimizers usually don't use indexes with OR predicates. 优化器通常不使用带有OR谓词的索引。

Try moving the categories.category_id = 1 into the join condition: 尝试将categories.category_id = 1移到联接条件中:

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. 该查询的关键字为1 in (ifnull(categories.category_id, primary_category_id), primary_category_id) ,它表示“如果我们加入了类别的连接,请在列表中使用它,否则使用primary_category_id,并且在所有情况下都使用primary_category_id 。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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