我是一个老派的MySQL用户,总是更喜欢JOIN而不是子查询。但是现在每个人都用子查询,我讨厌它;我不知道为什么。
我缺乏理论知识来判断是否有任何不同。子查询是否与JOIN一样好,因此没有什么可担心的?
我是一个老派的MySQL用户,总是更喜欢JOIN而不是子查询。但是现在每个人都用子查询,我讨厌它;我不知道为什么。
我缺乏理论知识来判断是否有任何不同。子查询是否与JOIN一样好,因此没有什么可担心的?
当前回答
如果你想用join加速你的查询:
对于“inner join/join”, 不要使用where条件,而是使用“ON”条件。 例如:
select id,name from table1 a
join table2 b on a.name=b.name
where id='123'
Try,
select id,name from table1 a
join table2 b on a.name=b.name and a.id='123'
对于“左/右连接”, 不要在“ON”条件下使用,因为如果你使用左/右连接,它将获得任何一个表的所有行。所以,在"开"里也没用。所以,尝试使用“Where”条件
其他回答
在大多数情况下,join比子查询快,子查询比子查询快的情况非常罕见。
在join中,RDBMS可以为您的查询创建一个更好的执行计划,并可以预测应该加载哪些数据来处理并节省时间,不像子查询,它将运行所有的查询并加载所有的数据来进行处理。
子查询的好处是它们比join更可读:这就是为什么大多数新学习SQL的人更喜欢它们;这是简单的方法;但是当涉及到性能时,join在大多数情况下更好,尽管它们也不难读。
首先,为了比较这两个,首先你应该区分查询和子查询:
一个子查询类,它总是使用连接编写相应的等效查询 不能使用连接重写的子查询类
对于第一类查询,一个好的RDBMS将把联接查询和子查询视为等效的,并将产生相同的查询计划。
现在甚至mysql也这么做了。
尽管如此,有时它并不会,但这并不意味着连接总是会赢-我有在mysql中使用子查询提高性能的情况。(例如,如果有一些东西阻止mysql计划器正确估计成本,如果计划器没有看到连接变量和子查询变量相同,那么子查询可以通过强制某个路径来优于连接)。
结论是,如果您想确定哪一种查询性能更好,就应该同时测试连接和子查询变量。
对于第二个类,比较没有意义,因为这些查询不能使用连接重写,在这种情况下,子查询是完成所需任务的自然方式,您不应该歧视它们。
子查询通常用于将单行作为原子值返回,不过它们也可以用于用IN关键字比较多行之间的值。在SQL语句中几乎任何有意义的地方都允许使用它们,包括目标列表、WHERE子句等等。一个简单的子查询可以用作搜索条件。例如,在一对表之间:
SELECT title
FROM books
WHERE author_id = (
SELECT id
FROM authors
WHERE last_name = 'Bar' AND first_name = 'Foo'
);
注意,在子查询的结果上使用普通值操作符要求只返回一个字段。如果你想检查一个值是否存在于一组其他值中,请使用in:
SELECT title
FROM books
WHERE author_id IN (
SELECT id FROM authors WHERE last_name ~ '^[A-E]'
);
这显然不同于LEFT-JOIN,你只是想连接表a和表B的东西,即使连接条件在表B中没有找到任何匹配的记录,等等。
如果你只是担心速度,你必须检查你的数据库,写一个好的查询,看看是否有显著的性能差异。
在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语句中,那么它可能会大大提高性能。
我不是关系数据库专家,所以对此持保留态度。
子查询与连接的一般思想是较大查询的求值路径。
为了执行较大的查询,必须首先执行每个子查询,然后将结果集存储为与较大查询交互的临时表。
这个临时表没有索引,因此,任何比较都需要扫描整个结果集。
相反,当您使用连接时,所有索引都在使用中,因此,比较需要遍历索引树(或哈希表),这在速度方面成本要低得多。
现在,我不知道最流行的关系引擎的新版本是否在反向执行求值,只是将必要的元素加载到临时表中,作为优化方法。