如何使用/ JOIN改进SQL查询?

时间:2011-04-27 12:47:58

标签: mysql sql grails

我正在使用MySQL 5.5。我有这3个表:新闻,NewsSubTopic,SubTopic。我想知道为什么这个查询很慢:

SELECT
  DISTINCT COUNT(news0_.id) as col_0_0_ 
FROM
  news news0_
INNER JOIN
  news_sub_topic subtopics1_ 
ON
  news0_.id = subtopics1_.news_sub_topics_id
INNER JOIN
  sub_topic subtopic2_ 
ON
  subtopics1_.sub_topic_id = subtopic2_.id 
WHERE
  (subtopic2_.id IN (55 , 134 , 135 , 52 , 53 , 32 , 54))
  AND news0_.type = 'api';

我已经在news.type中放置了索引键。是否可以在NewsSubTopic中添加密钥?

以下是一些统计信息:新闻表有 1,088,126 条目,NewsSubTopic有 823,247 条目,SubTopic有 168

请注意,该查询是由Grails(或Hibernate)生成的。你能解释一下如何调试查询并理解它为什么慢(3-5秒)?还有其他方法可以改进它(我可以提供您需要的其他信息)。

3 个答案:

答案 0 :(得分:4)

您不需要DISTINCTCOUNT的参数或对sub_topic的引用:

SELECT  COUNT(*)
FROM    news_sub_topic ns
JOIN    news n
ON      n.id = ns.news_sub_topics_id
WHERE   ns.sub_topic_id IN (55 , 134 , 135 , 52 , 53 , 32 , 54)
        AND n.type = 'api'

news_sub_topic (sub_topic_id, news_sub_topics_id)

上创建综合索引

请注意,DISTINCT COUNT(…)COUNT(DISTINCT …)是不同的事情。如果您需要后者,请使用:

SELECT  COUNT(DISTINCT n.id)
FROM    news_sub_topic ns
JOIN    news n
ON      n.id = ns.news_sub_topics_id
WHERE   ns.sub_topic_id IN (55 , 134 , 135 , 52 , 53 , 32 , 54)
        AND n.type = 'api'

您能解释一下您想对查询做什么吗?

答案 1 :(得分:1)

尽管已经说过,但您的查询可能不是Sargable。 您需要为连接条件创建索引,以使您查询尽可能不敏感的news_sub_topics_id。

确保也使用非常有选择性的索引(按选择性排序索引字段(VerySelective,LessSelective,...)。

答案 2 :(得分:0)

我不明白你为什么要这样做:

        ...
        ON
        news0_.id = subtopics1_.news_sub_topics_id

不是NEWS.id不是它的PK而且在加入主题时你不想再使用像NEWS.topicid这样的专栏吗?

您可以先尝试剔除子主题:

            select distinct newssubtopicid from newssubtopic as NS
            inner join subtopic ST on NS.subtopicid = ST.id
            and ST.id in (55 , 134 , 135 , 52 , 53 , 32 , 54)
ST.id是它的PK,不是吗? NS.subtopicid应该有一个索引。上面的查询需要多长时间?

此时,您知道提取相关新闻所需的新闻子主题:

          select count(NEWS.id) from NEWS
          inner join 
          (
            select distinct newssubtopicid from newssubtopic as NS
            inner join subtopic ST on NS.subtopicid = ST.id
            and ST.id in (55 , 134 , 135 , 52 , 53 , 32 , 54)
          ) as T
          on NEWS.topicid = T.newssubtopicid