2013-03-20 124 views
1

(可能是重复的,但我只能找到与JOIN [3]的问题和解决方案,这就是不是一个选项哪个子查询更快?

我有两个表。非常薄(很少列)和非常长(很多行)。一个是数据表(articles),另一个是ACL表(acl)。

我想只显示通过acl.some_id访问的文章。哪个子查询更快?

[1] 
SELECT a.title 
FROM articles a 
WHERE 0 < (
    SELECT COUNT(1) 
    FROM acl 
    WHERE article_id = a.id AND some_id IN (1, 2, 3) 
) 

[2] 
SELECT a.title 
FROM articles a 
WHERE a.id IN (
    SELECT article_id 
    FROM acl WHERE some_id IN (1, 2, 3) 
) 

我心中想说的第二个,因为子查询可重复使用的所有潜在的匹配行,因此将只执行一次(虽然结果集将是非常大的),而第一个子查询将不得不检查每一个可能匹配的行。

还有第三种方法,但这是不是一个选项,因为它会重复行(和GROUP BY不是解决方案,因为我需要COUNT以后的其他东西(和DISTINCT永远不是解决方案!)):

[3] 
SELECT a.title 
FROM articles a 
JOIN acl 
    ON acl.article_id = a.id 
WHERE acl.some_id IN (1, 2, 3) 

由于article_id的X存在N次acl,它将返回该行0 - N次,而不是0 - 1

还有第四个方法:EXISTS。感谢ypercube。

相关:

+5

你写的代码... **尝试它,并找出来!** – 2013-03-20 22:20:07

+0

尝试一次或15次并不意味着什么。我想要为什么。而且这些表格还不长=),所以执行时间将非常非常短。 – Rudie 2013-03-20 22:21:32

+3

mysql拥有你需要自己回答这个问题的所有工具。查看每个查询的执行计划。查看执行时间。你可以这样做。 – 2013-03-20 22:24:11

回答

5

我要说[2],太,但MySQL有优化IN子查询,至少高达5.5的一些盲点。 (新发布的)5.6版本中查询优化器有几项改进。您可以在MySQL文档中阅读关于(semijoins和IN子查询):MySQL 5.6: Optimizing Subqueries with Semi-Join Transformations

MariaDB(版本5.3和5.5)中的优化器也有一些改进,其中一些与这类查询有关。您可以在他们的文档中阅读:MariaDB 5.3: Semi-join subquery optimizations

您也可以尝试EXISTS版本,特别是如果你使用的是5.5或以上版本:

-- [4] 
SELECT id 
FROM articles AS a 
WHERE EXISTS (
    SELECT * 
    FROM acl 
    WHERE acl.some_id IN (1, 2, 3) 
    AND acl.article_id = a.id 
) ; 

我觉得(article_id, some_id)指数将在这里有用的 - 或者相反的一个,它不伤害尝试两个。


如果从acl (article_id) REFERENCES article (id)外键,你可以信任,而你只需要在文章的ID,你也可以只从一个表中的数据:

SELECT DISTINCT article_id 
FROM acl 
WHERE acl.some_id IN (1, 2, 3) ; 

当然你应该测试你服务器中的几个版本,你有(或计划使用)的MySQL版本,数据分布,当然还有足够大的表格。用几百行进行测试不会告诉你很多。

+0

啊是的EXISTS,这也是一个选项。听起来就像它是为了做到这一点。 (我有那些索引btw。) – Rudie 2013-03-20 22:29:02

+0

存在,我认为。显然比IN + COUNT快得多:http://www.jortk.nl/2008/07/exists-much-faster-then-in-in-mysql/(尽管这很旧)。可能是因为EXISTS在找到1条记录后停止/返回。 – Rudie 2013-03-20 22:31:58

+0

最后一个查询(仅返回文章ID)是不够的,因为我想要的不仅仅是文章ID。抱歉。不够明显。 – Rudie 2013-03-20 22:36:44