显式和隐式内部联接是否存在效率差异?
例如:
1 2 3
| SELECT * FROM
TABLE a INNER JOIN TABLE b
ON a.id = b.id; |
与
1 2 3
| SELECT a.*, b.*
FROM TABLE a, TABLE b
WHERE a.id = b.id; |
在性能方面,它们是完全相同的(至少在SQL Server中)。
PS:请注意,自SQL Server 2005起不推荐使用IMPLICIT OUTER JOIN语法。(仍支持问题中使用的IMPLICIT INNER JOIN语法)
弃用"旧样式" JOIN语法:只是部分事情
就我个人而言,我更喜欢连接语法,因为它可以更清楚地表明表是如何连接以及如何连接的。尝试比较较大的SQL查询,从8个不同的表中进行选择,然后在where中进行大量筛选。通过使用联接语法,您可以将联接表的部分分离到要过滤行的部分。
在MySQL 5.1.51上,两个查询的执行计划相同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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行。
这是一个非常简单的情况;它绝不证明查询优化器不会在更复杂的情况下产生混乱并生成不同的计划。
第二种语法具有交叉联接的可能性:您可以将表添加到FROM部分,而无需相应的WHERE子句。这被认为是有害的。
您给出的第一个答案使用了所谓的ANSI连接语法,另一个答案有效并且可以在任何关系数据库中使用。
我同意grom,您应该使用ANSI连接语法。正如他们所说,主要原因是为了清晰。而不是拥有带有很多谓词的where子句,其中一些联接表和其他限制了使用ANSI联接语法返回的行,而是使您盲目地弄清楚了哪些条件正在用于联接表,哪些条件用于限制表。结果。
@lomaxx:只是为了澄清一下,我很确定SQL Serv 2005支持上述两种语法。但是不支持以下语法
1 2 3
| SELECT a.*, b.*
FROM TABLE a, TABLE b
WHERE a.id *= b.id; |
具体来说,不支持外部联接(* =)。
Performance wise, they are exactly the same (at least in SQL Server) but be aware that they are deprecating this join syntax and it's not supported by sql server2005 out of the box.
我认为您正在考虑不赞成使用的* =和= *运算符与"外部连接"。
我刚刚测试了给定的两种格式,它们在SQL Server 2008数据库上可以正常工作。以我为例,他们得出了相同的执行计划,但是我不能自信地说这永远是正确的。
在某些数据库(尤其是Oracle)上,联接的顺序可能会对查询性能产生巨大的影响(如果有两个以上的表)。在一个应用程序上,在某些情况下,我们实际上有两个数量级的差异。如果使用正确的提示语法,则使用内部连接语法可让您对此进行控制。
您没有指定要使用的数据库,但是有可能表明SQL Server或MySQL没有什么实际的区别。
在性能方面,应该没有任何区别。显式联接语法对我来说似乎更干净,因为它在from子句中清楚地定义了表之间的关系,并且不会弄乱where子句。
正如Leigh Caldwell所说的那样,查询优化器可以根据功能上看起来像同一条SQL语句的内容生成不同的查询计划。有关此内容的更多信息,请查看以下两个博客文章:
Oracle Optimizer团队的一篇帖子
来自"结构化数据"博客的另一篇文章
希望您觉得这很有趣。
基本上,两者之间的区别在于,一种是以旧的方式编写的,而另一种是以现代的方式编写的。就我个人而言,我更喜欢使用内部,左侧,外部,右侧定义的现代脚本,因为它们更具解释性,并且使代码更具可读性。
当处理内部联接时,可读性也没有真正的区别,但是,在处理左右联接时,它可能会变得复杂,因为在较旧的方法中,您将得到如下所示:
1 2 3
| SELECT *
FROM TABLE a, TABLE b
WHERE a.id = b.id (+); |
上面是写左连接的旧方法,而不是下面的方法:
1 2 3
| SELECT *
FROM TABLE a
LEFT JOIN TABLE b ON a.id = b.id; |
如您所见,脚本的现代编写方式使查询更具可读性。 (顺便说一句,对于右联接,对于外联接,则稍微复杂一些)。
回到样板,对于SQL编译器,以相同的方式处理查询,如何编写查询没有影响。我已经在Oracle数据库中看到了两者的混合情况,这些数据库中有很多人在写它,无论是老年人还是年轻人。同样,它归结为脚本的可读性以及与您一起开发的团队的可读性。
以我的经验,使用子句中的交叉联接常常会导致大脑受损的执行计划,尤其是在使用Microsoft SQL产品的情况下。例如,SQL Server尝试估算表行数的方法非常可怕。使用内部联接语法使您可以控制查询的执行方式。因此,从实际的角度来看,鉴于当前数据库技术的简单性,您必须使用内部联接。