【问题标题】:MySQL "in-where" is slow?MySQL“在哪里”很慢?
【发布时间】:2015-04-30 06:45:53
【问题描述】:

我有两个表:PostsTags,它们存储用户发布的文章以及他们附加到文章的标签。一个表PostTags用来表示文章ID和标签ID的关系。结构如下:

帖子:

id | title | author_id | create_time | update_time | ... #(title, author_id, create_time) is unique

标签:

id | tag_text | create_time #tag_text is unique and index

帖子标签:

id | post_id | tag_id #(post_id, tag_id) is unique

我现在使用下面的sql来获取带有相应标签的文章(使用group_concat)。

SELECT p.id, p.title, t.tag AS Tags FROM Posts p 
LEFT JOIN Tags t on t.id IN 
    (SELECT tag_id FROM PostTags WHERE post_id=s.id) 
GROUP BY p.id ORDER BY p.update_time DESC LIMIT 0, 10

但我发现它非常慢(对于 2.5k 行文章和 600 个标签,它需要 >3s)。如何提高性能?

EXPLAIN结果如下:

id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra

1 | PRIMARY | p | ALL | NULL | NULL | NULL | NULL | 2569 | Using temporary; Using filesort

1 | PRIMARY | t | ALL | NULL | NULL | NULL | NULL | 616   

2 | DEPENDENT SUBQUERY | PostTags | index_subquery | unique_index,tag_id,post_id | 
tag_id | 4 | func | 1 | Using where

PS,我原来的sql是(with group_concat)

SELECT p.id, p.title, group_concat(DINSTINCT t.tag) AS Tags FROM Posts p 
LEFT JOIN Tags t on t.id IN 
    (SELECT tag_id FROM PostTags WHERE post_id=s.id) 
GROUP BY p.id ORDER BY p.update_time DESC LIMIT 0, 10

但是没有 group_concat 的情况是一样的。

【问题讨论】:

  • 您在查询中使用 group_concat 的位置???
  • 哎呀,本来我以为 group_concat 会有影响;但是在我发布这个问题的过程中,我尝试了没有 group_concat 的案例,但发现它仍然很慢。所以这个问题有些不一致。刚刚编辑。

标签: php mysql


【解决方案1】:

MySQL documentation describes exactly this kind of situation:

IN 子查询性能不佳的典型情况是子查询返回少量行但外部查询返回大量行以与子查询结果进行比较。

问题在于,对于使用 IN 子查询的语句,优化器将其重写为相关子查询。 [..] 如果内部和外部查询分别返回 M 和 N 行,则执行时间变为 O(M×N) 的量级,而不是 O(M+N)不相关的子查询

使用另一个连接而不是子查询将是一个更优化的解决方案:

SELECT p.id, p.title, t.tag AS Tags FROM Posts p
LEFT JOIN PostTags pt on pt.post_id = p.id
LEFT JOIN Tags t on t.id = pt.tag_id
GROUP BY p.id ORDER BY p.update_time DESC LIMIT 0, 10

【讨论】:

  • 是的。现在是 0.03 秒。谢谢~
【解决方案2】:

这里是 group_concatgroup_concat 的查询没有什么要 与速度有关。

select
p.id,
p.title,
group_concat(t.tag_text) as post_tags
from Post p 
left join PostTags pt on pt.post_id = p.id
left join Tags t on pt.tag_id = t.id
group by p.id
order by p.udate_time desc 
limit 0,10

您的表上已经有一些索引,到目前为止还不错,但是添加另一个 索引将提升查询

alter table Posts add index updated_time_idx(updated_time);

【讨论】:

    猜你喜欢
    • 2013-02-11
    • 2015-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-01
    • 2013-07-30
    • 1970-01-01
    • 2013-08-03
    相关资源
    最近更新 更多