显式与隐式SQL连接

显式内连接和隐式内连接的效率有什么不同吗? 例如:< / p >
SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

vs。

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;
209649 次浏览

在性能方面,它们是完全相同的(至少在SQL Server中)。

注:请注意,自SQL Server 2005以来,IMPLICIT OUTER JOIN语法已弃用。(问题中使用的IMPLICIT INNER JOIN语法仍然被支持)

"Old Style" JOIN语法的弃用:Only a Partial Thing .

就我个人而言,我更喜欢join语法,因为它更清楚地表明表是连接的以及它们是如何连接的。尝试比较更大的SQL查询,其中您从8个不同的表中选择,并且在where中有很多过滤。通过使用联接语法,可以分离出连接表的部分和过滤行的部分。

在性能方面,它们是完全相同的(至少在SQL Server中),但要注意,它们不支持这种连接语法,而且SQL server2005不支持开箱即用的连接语法。

我认为您想到的是已弃用的*=和=*操作符vs。“外连接”。

我刚刚测试了给出的两种格式,它们在SQL Server 2008数据库上正常工作。在我的案例中,他们得到了相同的执行计划,但我不能肯定地说这总是正确的。

在一些数据库(尤其是Oracle)中,连接的顺序会对查询性能产生巨大的影响(如果有两个以上的表)。在一个应用程序中,我们在某些情况下有两个数量级的差异。如果使用正确的提示语法,使用内部连接语法可以控制这一点。

您没有指定使用哪个数据库,但可能建议使用SQL Server或MySQL,在那里它没有真正的区别。

@lomaxx:澄清一下,我非常确定SQL Serv 2005支持上述两种语法。但是不支持下面的语法

select a.*, b.*
from table a, table b
where a.id *= b.id;

具体来说,不支持外部连接(*=)。

你给出的第一个答案使用了所谓的ANSI连接语法,另一个是有效的,可以在任何关系数据库中工作。

我同意grom的观点,你应该使用ANSI连接语法。正如他们所说,主要原因是为了清晰。与其使用带有大量谓词的where子句(其中一些用于连接表,另一些用于限制ANSI连接语法返回的行),不如盲目地明确哪些条件用于连接表,哪些条件用于限制结果。

正如Leigh Caldwell所述,查询优化器可以根据功能上类似于相同SQL语句的内容生成不同的查询计划。欲进一步阅读,请参阅以下两篇博客文章:-

一篇来自Oracle优化团队的帖子

另一篇来自"结构化数据"博客的帖子

我希望你会觉得这很有趣。

第二种语法具有不必要的交叉连接的可能性:您可以向FROM部分添加表而不对应WHERE子句。这被认为是有害的。

就性能而言,它不应该有任何区别。显式连接语法对我来说似乎更干净,因为它清楚地定义了from子句中表之间的关系,并且没有混淆where子句。

在MySQL 5.1.51中,两个查询有相同的执行计划:

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)


mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1有166208行;table2大约有1000行。

这是一个非常简单的例子;这并不能证明查询优化器在更复杂的情况下不会感到困惑并生成不同的计划。

根据我的经验,使用带有where子句的交叉连接语法通常会导致执行计划受到破坏,特别是在使用Microsoft SQL产品时。例如,SQL Server试图估计表行数的方法非常可怕。使用内部连接语法可以在一定程度上控制查询的执行方式。因此,从实用的角度来看,鉴于当前数据库技术的返祖性质,您必须使用内部连接。

基本上,两者之间的区别是一个是用旧的方式写的,而另一个是用现代的方式写的。就我个人而言,我更喜欢使用内、左、外、右定义的现代脚本,因为它们更具解释性,并且使代码更具可读性。

当处理内部连接时,在可读性上也没有真正的区别,然而,当处理左连接和右连接时可能会变得复杂,因为在旧的方法中,你会得到这样的东西:

SELECT *
FROM table a, table b
WHERE a.id = b.id (+);

上面是左连接的旧写法,而不是下面的写法:

SELECT *
FROM table a
LEFT JOIN table b ON a.id = b.id;

正如您可以直观地看到的,编写脚本的现代方式使查询更具可读性。(顺便说一下,右连接也是一样的,外连接稍微复杂一点)。

回到锅炉板,查询的编写方式对SQL编译器来说并没有什么不同,因为它以相同的方式处理查询。我在Oracle数据库中看到了两者的混合,有很多人在其中写东西,有年长的也有年轻的。同样,这可以归结为脚本的可读性以及与您一起开发的团队。