我是一个老派的MySQL用户,总是更喜欢JOIN而不是子查询。但是现在每个人都用子查询,我讨厌它;我不知道为什么。
我缺乏理论知识来判断是否有任何不同。子查询是否与JOIN一样好,因此没有什么可担心的?
我是一个老派的MySQL用户,总是更喜欢JOIN而不是子查询。但是现在每个人都用子查询,我讨厌它;我不知道为什么。
我缺乏理论知识来判断是否有任何不同。子查询是否与JOIN一样好,因此没有什么可担心的?
当前回答
子查询是解决“从A获取事实,以B的事实为条件”这种形式的问题的逻辑正确方法。在这种情况下,在子查询中插入B比进行连接更具逻辑意义。从实际意义上讲,它也更安全,因为您不必担心由于与B的多个匹配而从a获得重复的事实。
然而,实际上,答案通常归结于性能。当给出连接和子查询时,一些优化器会很糟糕,而另一些则相反,这是特定于优化器、特定于dbms版本和特定于查询的。
从历史上看,显式连接通常会胜出,因此已经建立的智慧是连接更好,但优化器一直在变得更好,因此我更喜欢先以逻辑一致的方式编写查询,然后在性能限制的情况下重新构造查询。
其他回答
子查询通常用于将单行作为原子值返回,不过它们也可以用于用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中没有找到任何匹配的记录,等等。
如果你只是担心速度,你必须检查你的数据库,写一个好的查询,看看是否有显著的性能差异。
我只是在考虑同样的问题,但我在FROM部分使用子查询。 我需要连接和查询大表,“从”表有2800万条记录,但结果只有128个这样小的结果大数据!我在它上面使用MAX()函数。
首先,我使用LEFT JOIN,因为我认为这是正确的方式,mysql可以优化等。 第二次只是为了测试,我重写了针对JOIN的子选择。
LEFT JOIN运行时:1.12s SUB-SELECT运行时间:0.06秒
子选择比连接快18倍!只是在chokito广告。subselect看起来很糟糕,但结果…
首先,为了比较这两个,首先你应该区分查询和子查询:
一个子查询类,它总是使用连接编写相应的等效查询 不能使用连接重写的子查询类
对于第一类查询,一个好的RDBMS将把联接查询和子查询视为等效的,并将产生相同的查询计划。
现在甚至mysql也这么做了。
尽管如此,有时它并不会,但这并不意味着连接总是会赢-我有在mysql中使用子查询提高性能的情况。(例如,如果有一些东西阻止mysql计划器正确估计成本,如果计划器没有看到连接变量和子查询变量相同,那么子查询可以通过强制某个路径来优于连接)。
结论是,如果您想确定哪一种查询性能更好,就应该同时测试连接和子查询变量。
对于第二个类,比较没有意义,因为这些查询不能使用连接重写,在这种情况下,子查询是完成所需任务的自然方式,您不应该歧视它们。
使用EXPLAIN查看数据库如何对数据执行查询。这个答案中有一个很大的“视情况而定”……
PostgreSQL可以将子查询重写为连接,或将连接重写为子查询,如果它认为其中一个比另一个快。这完全取决于数据、索引、相关性、数据量、查询等。
在旧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。