我是一个老派的MySQL用户,总是更喜欢JOIN而不是子查询。但是现在每个人都用子查询,我讨厌它;我不知道为什么。
我缺乏理论知识来判断是否有任何不同。子查询是否与JOIN一样好,因此没有什么可担心的?
我是一个老派的MySQL用户,总是更喜欢JOIN而不是子查询。但是现在每个人都用子查询,我讨厌它;我不知道为什么。
我缺乏理论知识来判断是否有任何不同。子查询是否与JOIN一样好,因此没有什么可担心的?
当前回答
现在,许多dbs都可以优化子查询和连接。因此,您只需使用explain检查您的查询,看看哪个更快。如果在性能上没有太大的差异,我更喜欢使用子查询,因为它们简单,更容易理解。
其他回答
在旧Mambo CMS的一个非常大的数据库上运行:
SELECT id, alias
FROM
mos_categories
WHERE
id IN (
SELECT
DISTINCT catid
FROM mos_content
);
0秒
SELECT
DISTINCT mos_content.catid,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
~ 3秒
EXPLAIN说明它们检查的行数完全相同,但其中一个需要3秒,另一个几乎是即时的。这个故事的寓意?如果性能很重要(什么时候不重要?),尝试多种方法,看看哪一种最快。
和…
SELECT
DISTINCT mos_categories.id,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
0秒
同样,结果相同,检查的行数相同。我猜是DISTINCT mos_content。catid比DISTINCT mos_categories需要更长的时间来计算。id。
摘自MySQL手册(13.2.10.11将子查询重写为连接):
LEFT [OUTER] JOIN可以比等效的子查询更快,因为服务器可以更好地优化它——这不是MySQL服务器独有的事实。
所以子查询可能比LEFT [OUTER] 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语句中,那么它可能会大大提高性能。
子查询能够动态地计算聚合函数。 例如,找到这本书的最低价格,并得到所有以这个价格出售的书。 1)使用子查询:
SELECT titles, price
FROM Books, Orders
WHERE price =
(SELECT MIN(price)
FROM Orders) AND (Books.ID=Orders.ID);
2)使用join
SELECT MIN(price)
FROM Orders;
-----------------
2.99
SELECT titles, price
FROM Books b
INNER JOIN Orders o
ON b.ID = o.ID
WHERE o.price = 2.99;
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代替。在其他情况下,这没有什么区别。
我说:为子查询创建函数可以消除混乱的问题,并允许您为子查询实现额外的逻辑。因此,我建议尽可能为子查询创建函数。
代码中的混乱是一个大问题,几十年来业界一直在努力避免它。