优化主id关系表

时间:2015-01-01 10:42:38

标签: mysql sql database

tag_relation表只有tag_id和comment_id字段 ,并且它们都被编入索引。 (没有主要的)它有InnoDB类型。

以下查询需要很长时间才能执行。我怎样才能让它更快?

所有comment_id,tag_id,status,datetime字段都已编制索引。我真的不知道如何进一步优化它。

SELECT
    text
FROM comment
INNER JOIN tag_relation
    ON tag_relation.comment_id=comment.comment_id
WHERE tag_id='1022278'
AND status=1
ORDER BY comment.datetime DESC LIMIT 0,20

缓慢的主要原因是tag_relation表,它有150万条记录。当记录较少时,执行时间会更快。

查询计划:

3 个答案:

答案 0 :(得分:3)

这是您的查询:

SELECT c.text
FROM comment c INNER JOIN
     tag_relation tr
     ON tr.comment_id = c.comment_id
WHERE t.tag_id = 1022278 AND c.status = 1
ORDER BY c.datetime DESC
LIMIT 0, 20;

首先,请注意我从值1022278中删除了单引号。如果这确实是一个数字,单引号有时会混淆SQL优化器。根据各种条件的选择性,有两种方法可以优化此查询。第一个是索引:

tag_relation(tag_id, comment_id)
comment(comment_id, status, datetime, text)

第二个是评论的覆盖索引,最重要的部分是comment_id列。

第二个是:

comment(status, comment_id, datetime)
tag_relation(comment_id, tag_id)

基本问题是首先为join扫描表。使用此索引,查询将被处理为:

SELECT c.text
FROM comment c INNER JOIN
     tag_relation
WHERE c.status = 1 AND
      EXISTS (SELECT 1
              FROM tag_relation tr
              WHERE tr.comment_id = c.comment_id AND tr.tag_id = 1022278 
             )
ORDER BY c.datetime DESC
LIMIT 0, 20;

我不是100%确定这会避免对结果集进行文件排序,但它可能会有效。

答案 1 :(得分:2)

如果我做得对,你有一个tag_id索引和另一个comment_id索引。尝试创建一个复合索引,如:

create index ... on tag_relation(tag_id, comment_id)

这将使tag_id的索引成为冗余,因此可以将其删除。

AFAIK MySQL无法进行索引编排,但即使它可以复合索引也会更有效率。

答案 2 :(得分:1)

我认为问题出在“状态”字段中。虽然它已编入索引,但索引未被使用。它说该表的“使用位置”。您可以强制使用索引进行状态,但我不确定它是否有用,具体取决于选择性,即“状态”可以采用多少个不同的值。或者,文档说如果“status”允许NULL,那么你会看到“using where”。是否允许NULL?如果是这样,请考虑限制它。

我刚注意到我忽略了“ORDER BY”,comment.datetime需要一个索引。

如果您已有索引,请尝试子查询:

SELECT     text
FROM       tag_relation
INNER JOIN (SELECT c.comment_id, c.text, c.datetime
            FROM comment c
            WHERE c.status = 1) comment
        ON tag_relation.comment_id = comment.comment_id
WHERE tag_id='1022278'
ORDER BY comment.datetime DESC LIMIT 0,20