显式与隐式SQL联接

显式与隐式SQL联接,sql,join,Sql,Join,显式与隐式内部联接是否有效率差异? 例如: SELECT * FROM table a INNER JOIN table b ON a.id = b.id; vs 就性能而言,它们至少在SQL Server中完全相同 PS:请注意,自SQLServer2005以来,隐式外部联接语法已被弃用。仍然支持问题中使用的隐式内部联接语法 就我个人而言,我更喜欢联接语法,因为它使表的联接和联接方式更加清晰。尝试比较较大的SQL查询,从8个不同的表中进行选择,然后在其中进行大量筛选。通过使用连接语法,可以将

显式与隐式内部联接是否有效率差异? 例如:

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


就性能而言,它们至少在SQL Server中完全相同

PS:请注意,自SQLServer2005以来,隐式外部联接语法已被弃用。仍然支持问题中使用的隐式内部联接语法


就我个人而言,我更喜欢联接语法,因为它使表的联接和联接方式更加清晰。尝试比较较大的SQL查询,从8个不同的表中进行选择,然后在其中进行大量筛选。通过使用连接语法,可以将表连接的部分与筛选行的部分分开


就性能而言,它们至少在SQL Server中是完全相同的,但请注意,它们不支持这种联接语法,SQL Server 2005不支持这种现成的联接语法

我认为您正在考虑弃用的*=和=*运算符与外部联接


我刚刚测试了给定的两种格式,它们可以在SQLServer2008数据库上正常工作。在我的例子中,它们产生了相同的执行计划,但我不能自信地说这总是正确的。

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


您没有指定正在使用哪个数据库,但概率表明SQL Server或MySQL在哪里没有真正的区别。

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

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

具体地说,不支持外部联接*=。

您给出的第一个答案使用了ANSI联接语法,另一个是有效的,可以在任何关系数据库中使用


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

如Leigh Caldwell所述,查询优化器可以根据功能上类似于同一SQL语句的内容生成不同的查询计划。要进一步了解这一点,请查看以下两篇博客帖子:-


我希望您会对此感兴趣。

第二种语法存在不必要的交叉连接的可能性:您可以向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)
表1有166208行;表2大约有1000行


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

根据我的经验,使用交叉连接-with-a-where-clause语法通常会产生大脑受损的执行计划,尤其是在使用Microsoft SQL产品时。例如,SQLServer试图估计表行数的方式非常可怕。使用内部联接语法可以控制查询的执行方式。因此,从实用的角度来看,考虑到当前数据库技术的返祖特性,您必须使用内部连接。

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

在处理内部联接时,可读性也没有真正的区别,但是,在处理左联接和右联接时,可能会变得复杂,因为在旧方法中,您会得到如下结果:

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数据库中看到了两者的混合,有很多人在其中写入,包括老年人和年轻人。同样,它可以归结为脚本的可读性和您所领导的团队

使用.

Leigh进行开发时,您也可以在隐式联接中使用提示。在Oracle中,联接顺序以有意义的方式影响执行计划的情况极为罕见。请参见Jonathan Lewis的解释。Mike,他们讨论的区别在于,如果指定显式连接,则需要指定要连接的连接条件,而不是筛选器。您会注意到,对于语义正确的查询,exec计划是相同的。坦率地说,即使在SQLServer2000中,我也不会使用它,因为*=语法经常给出错误的答案。有时它会把这些解释为交叉连接。好问题。我很好奇为什么要使用显式连接。是否不可能在没有它的情况下执行所有查询?使用EXPLAIN关键字了解两个查询的区别。。使用JOIN并查看差异。。如果你在一个超过100k条记录的表中尝试,你会看到不同之处…@andrew我的问题实际上是隐式连接是否是一种黑客行为,就像在一个涉及多个表的查询中,不使用连接一样?这是一种攻击,不是吗?它们是不同的,当处理空值时,隐式连接偶尔会让你感到惊讶;使用显式连接,避免在没有任何更改时出现错误!没有区别,是交叉连接,具有较松的绑定;内部连接是交叉连接,具有相同的位置,但具有较紧的绑定。对于执行来说,重要的是DBMS如何优化查询。@lomaxx,为了清楚起见,您能否指定问题中2的哪种语法是不推荐的?您能否提供支持文档?这听起来在多个层面上都是错误的。你是如何反对SQL标准的?@david Crenshaw,隐式连接已经不在标准中了,而且已经18年没有了。所谓的“内部”或“交叉”类型的隐式连接仍然在标准中。SQL Server正在弃用旧式的外部联接语法,即。*=和=*,这从来都不是标准语法。您有任何证据证明这一点吗?因为相反。如果from子句中的表名是从where子句中使用的表生成的呢?您也可以使用显式连接语法进行交叉连接。你可能是说它不那么严格,因此更容易出现用户错误。我完全同意,但这有点离题。OP询问效率。这应该是公认的答案。这是正确的,该计划与较大的报表相同或接近,但记录量将非常大,从而导致性能差异。
SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;