我是一个老派的MySQL用户,总是更喜欢JOIN而不是子查询。但是现在每个人都用子查询,我讨厌它;我不知道为什么。
我缺乏理论知识来判断是否有任何不同。子查询是否与JOIN一样好,因此没有什么可担心的?
我是一个老派的MySQL用户,总是更喜欢JOIN而不是子查询。但是现在每个人都用子查询,我讨厌它;我不知道为什么。
我缺乏理论知识来判断是否有任何不同。子查询是否与JOIN一样好,因此没有什么可担心的?
当前回答
子查询是解决“从A获取事实,以B的事实为条件”这种形式的问题的逻辑正确方法。在这种情况下,在子查询中插入B比进行连接更具逻辑意义。从实际意义上讲,它也更安全,因为您不必担心由于与B的多个匹配而从a获得重复的事实。
然而,实际上,答案通常归结于性能。当给出连接和子查询时,一些优化器会很糟糕,而另一些则相反,这是特定于优化器、特定于dbms版本和特定于查询的。
从历史上看,显式连接通常会胜出,因此已经建立的智慧是连接更好,但优化器一直在变得更好,因此我更喜欢先以逻辑一致的方式编写查询,然后在性能限制的情况下重新构造查询。
其他回答
现在,许多dbs都可以优化子查询和连接。因此,您只需使用explain检查您的查询,看看哪个更快。如果在性能上没有太大的差异,我更喜欢使用子查询,因为它们简单,更容易理解。
我只是在考虑同样的问题,但我在FROM部分使用子查询。 我需要连接和查询大表,“从”表有2800万条记录,但结果只有128个这样小的结果大数据!我在它上面使用MAX()函数。
首先,我使用LEFT JOIN,因为我认为这是正确的方式,mysql可以优化等。 第二次只是为了测试,我重写了针对JOIN的子选择。
LEFT JOIN运行时:1.12s SUB-SELECT运行时间:0.06秒
子选择比连接快18倍!只是在chokito广告。subselect看起来很糟糕,但结果…
MSDN文档SQL Server说
Many Transact-SQL statements that include subqueries can be alternatively formulated as joins. Other questions can be posed only with subqueries. In Transact-SQL, there is usually no performance difference between a statement that includes a subquery and a semantically equivalent version that does not. However, in some cases where existence must be checked, a join yields better performance. Otherwise, the nested query must be processed for each result of the outer query to ensure elimination of duplicates. In such cases, a join approach would yield better results.
所以如果你需要
select * from t1 where exists select * from t2 where t2.parent=t1.id
尝试使用join代替。在其他情况下,这没有什么区别。
我说:为子查询创建函数可以消除混乱的问题,并允许您为子查询实现额外的逻辑。因此,我建议尽可能为子查询创建函数。
代码中的混乱是一个大问题,几十年来业界一直在努力避免它。
只有当第二个连接表的数据明显多于主表时,才会出现这种差异。我有过这样的经历……
我们有一个用户表,有10万个条目,他们的会员数据(友谊)大约有30万个条目。这是一个join语句,目的是获取好友及其数据,但有很大的延迟。但是当成员表中只有少量数据时,它工作得很好。一旦我们将其更改为使用子查询,它就可以正常工作。
但与此同时,连接查询正在处理比主表拥有更少条目的其他表。
所以我认为连接和子查询语句工作得很好,这取决于数据和情况。
在2010年,我会加入这个问题的作者,并强烈地投票给JOIN,但有了更多的经验(特别是在MySQL),我可以声明:是的,子查询可以更好。我在这里看到了很多答案;一些声明的子查询速度更快,但它缺乏一个很好的解释。我希望我能提供一个(非常)晚的答案:
首先,让我说一下最重要的一点:子查询有不同的形式
第二个重要的陈述:规模很重要
如果使用子查询,应该了解DB-Server如何执行子查询。特别是当子查询只计算一次或每一行时! 另一方面,现代DB-Server能够进行大量优化。在某些情况下,子查询有助于优化查询,但DB-Server的新版本可能会使优化过时。
选择字段中的子查询
SELECT moo, (SELECT roger FROM wilco WHERE moo = me) AS bar FROM foo
注意,对于foo生成的每一行都会执行子查询。 尽可能避免这种情况;它可能会大大降低你在大型数据集上的查询速度。但是,如果子查询没有对foo的引用,则可以由DB-server将其作为静态内容进行优化,并且只能求值一次。
where语句中的子查询
SELECT moo FROM foo WHERE bar = (SELECT roger FROM wilco WHERE moo = me)
如果幸运的话,DB会在内部将其优化为一个JOIN。如果不这样做,你的查询在庞大的数据集上会变得非常非常慢,因为它会对foo中的每一行执行子查询,而不是像在select类型中那样只执行结果。
join语句中的子查询
SELECT moo, bar
FROM foo
LEFT JOIN (
SELECT MIN(bar), me FROM wilco GROUP BY me
) ON moo = me
This is interesting. We combine JOIN with a sub-query. And here we get the real strength of sub-queries. Imagine a dataset with millions of rows in wilco but only a few distinct me. Instead of joining against a huge table, we have now a smaller temporary table to join against. This can result in much faster queries depending on database size. You can have the same effect with CREATE TEMPORARY TABLE ... and INSERT INTO ... SELECT ..., which might provide better readability on very complex queries (but can lock datasets in a repeatable read isolation level).
嵌套的子查询
SELECT VARIANCE(moo)
FROM (
SELECT moo, CONCAT(roger, wilco) AS bar
FROM foo
HAVING bar LIKE 'SpaceQ%'
) AS temp_foo
GROUP BY moo
您可以在多个级别中嵌套子查询。如果你必须对结果进行分组或更改,这可以帮助处理庞大的数据集。通常,DB-Server为此创建一个临时表,但有时不需要对整个表进行某些操作,只需要对结果集进行操作。这可能会提供更好的性能,具体取决于表的大小。
结论
子查询不能代替JOIN,您不应该这样使用它们(尽管有可能)。在我看来,子查询的正确用法是作为CREATE TEMPORARY TABLE ....的快速替换一个好的子查询以一种在JOIN的ON语句中无法完成的方式减少数据集。如果子查询具有GROUP BY或DISTINCT关键字之一,并且最好不在选择字段或where语句中,那么它可能会大大提高性能。