在MySQL查询中使用SELECT语句嵌套SELECT语句

4

通常使用SELECT语句嵌套SELECT语句以减少查询数量,但是经过我的检查发现这会导致慢查询(这显然对MySQL的性能有害)。我曾有一个简单的查询如下:

SELECT something
 FROM posts
 WHERE id IN (
  SELECT tag_map.id
  FROM tag_map
  INNER JOIN tags
  ON tags.tag_id=tag_map.tag_id
  WHERE tag IN ('tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6')
  )

这会导致查询变慢,出现“查询时间为3-4秒;锁定时间约为0.000090秒;检查了大约200行”的情况。
如果我将SELECT查询拆分,每个查询都会很快;但这会增加查询的数量,在高并发情况下不太好。
这是正常情况吗?还是我的编码有问题?

3
在SELECT语句中嵌套SELECT语句?!这就像电影《Inselection》中的情节。 - ta.speot.is
3个回答

13

在MySQL中,执行这样的子查询被称为“关联查询”。这意味着外部SELECT语句的结果取决于内部SELECT语句的结果。结果是你的内部查询将会对每一行进行一次执行,这非常慢。

你应该重构这个查询;无论是两次连接还是使用两个查询,都基本无关紧要。两次连接将给你:

SELECT something
FROM posts
INNER JOIN tag_map ON tag_map.id = posts.id
INNER JOIN tags ON tags.tag_id = tag_map.tag_id
WHERE tags.tag IN ('tag1', ...)

如需更多信息,请参阅MySQL手册上的将子查询转换为JOINs

提示:使用EXPLAIN SELECT可以查看优化器处理查询的计划。如果您看到了DEPENDENT SUBQUERY,则应进行重构,因为它们非常慢。


2
您可以通过使用以下方法来改进它:
SELECT something
FROM posts
INNER JOIN tag_map ON tag_map.id = posts.id
INNER JOIN tags
ON tags.tag_id=tag_map.tag_id
WHERE <tablename>.tag IN ('tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6')

请确保只选择所需内容,不要使用 * 通配符;同时指定标签列在哪个表中,以便替换<tablename>


这就是我们所说的 JOIN - Harry Joy
是的,内连接两次,至少我认为它比in子句更快。 - jclozano

1

Join 进行结果过滤。第一个 Join 会保留第一个 ON 条件满足的结果,然后第二个条件在第二个 ON 条件上给出最终结果。

SELECT something
FROM posts
INNER JOIN tag_map ON tag_map.id = posts.id
INNER JOIN tags ON tags.tag_id = tag_map.tag_id AND tags.tag IN ('tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6');

您可以在Stack Overflow上看到这些讨论:

question1 question2

使用Join可以降低时间复杂度并提高服务器的稳定性。

将子查询转换为Join的信息:

link1 link2 link3


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接