ANSI与非ANSI SQL JOIN语法

我拥有大约7000行T-SQL存储过程的业务逻辑,其中大部分都有下一个JOIN语法:

SELECT AA, BB, CC FROM aaa AS A, bbb AS B, ccc AS C WHERE AB = B.ID AND BC = C.ID AND C.ID = @param 

如果我用这个replace这样的查询,我会得到性能增长吗:

 SELECT AA, BB, CC FROM aaa AS A JOIN bbb AS B ON AB = B.ID JOIN ccc AS C ON BC = C.ID AND C.ID = @param 

或者他们是一样的?

这两个查询是相同的,除了第二个是ANSI-92 SQL语法,第一个是没有合并连接子句的较旧的SQL语法。 他们应该产生完全相同的内部查询计划,虽然你可能想检查。

您应该使用ANSI-92语法有几个原因

  • JOIN子句的使用将关系逻辑从filter逻辑(WHERE)中分离出来,因此更清晰,更易于理解。
  • 这个查询并不重要,但是在一些情况下,旧的外部连接语法(使用+)是不明确的,查询结果因此与实现相关 – 或者查询根本无法parsing。 ANSI-92不会出现这些情况
  • 这是很好的做法,因为大多数开发人员和dba将现在使用ANSI-92,你应该遵循标准。 当然,所有现代的查询工具都将生成ANSI-92。
  • 正如@gbn指出的那样,它倾向于避免意外的交叉连接。

我自己曾经抵制过ANSI-92一段时间,因为它对于旧的语法有一些概念上的优势,因为它更容易将SQL设想为所有使用过的表的大量笛卡尔连接,然后是一个过滤操作 – 一个有用的心理技术用于掌握SQL查询正在做什么。 不过,我在几年前决定,我需要与时俱进,经过相对较短的调整期后,我现在强烈地select – 主要是因为上述第一个原因。 唯一不应该使用ANSI-92语法的地方是使用自然连接,这是隐含危险的。

第二个构造在SQL社区中被称为“固定连接语法”。 第一个构造AFAIK没有被广泛接受的名字,所以我们称之为“老式”内部连接语法。

通常的论点是这样的:

“传统”语法的优点:谓词在WHERE子句中以任何顺序进行物理分组,在一般情况下,查询的顺序非常特殊,n-ary关系更容易阅读和理解(加载语法的ON子句可以分散谓词,所以你必须在可视距离上查找一个表或列的外观)。

“传统”语法的缺点:省略“连接”谓词之一时,不存在parsing错误,并且结果是笛卡尔积(在加载语法中称为CROSS JOIN ),这样的错误可能会很棘手,无法检测debugging。 此外,“连接”谓词和“过滤”谓词在WHERE子句中被物理地组合在一起,这可能导致它们彼此混淆。

执行并检查他们的查询计划。 他们应该是平等的。

两个查询相等的 – 第一个是使用非ANSI JOIN语法,第二个是ANSI JOIN语法。 我build议坚持使用ANSI JOIN语法。

是的,LEFT OUTER JOINs(其中,也是ANSI JOIN语法)是当您要join的表可能不包含任何匹配logging时您想要使用的。

参考: SQL Server中的条件连接

好的,他们执行相同的。 这是同意的。 不像许多我使用旧的约定。 SQL-92“更容易理解”是值得商榷的。 写了40年的编程语言(吞咽)我知道'易于阅读'首先开始,在任何其他约定之前,'视力'(这里误用了术语,但它是我可以使用的最好的短语)。 在读SQL的时候,你首先要关心的是表涉及到哪些表(大部分)定义了谷物。 然后你关心数据的相关约束,然后select属性。 虽然SQL-92主要将这些想法分离出来,但是有太多的噪音词汇,大脑的眼睛必须解释和处理这些,这使得读取SQL变得更慢。

 SELECT Mgt.attrib_a AS attrib_a ,Sta.attrib_b AS attrib_b ,Stb.attrib_c AS attrib_c FROM Main_Grain_Table Mgt ,Surrounding_TabA Sta ,Surrounding_tabB Stb WHERE Mgt.sta_join_col = Sta.sta_join_col AND Mgt.stb_join_col = Stb.stb_join_col AND Mgt.bus_logic_col = 'TIGHT' 

视力 将前面的新属性的逗号放在前面它使得注释代码更简单对函数和关键字使用特定的情况对表使用特定的情况对属性使用特定的情况垂直排列运算符和操作将FROM中的第一个表表示数据的粒度使WHERE的第一个表成为连接约束,并让特定的紧约束浮动到底部。 为数据库中的所有表select3个字符别名,并使用您引用表的别名(EVERYWHERE)。 您应该使用该别名作为该表上(许多)索引的前缀。 另外一个半打6个,对不对? 也许。 但是,即使你使用ANSI-92惯例(正如我已经有的情况下将继续这样做),使用视力原理,垂直排列让你的大脑的眼睛避开你想看到的地方,并容易避免的东西(特别是噪音词)你不需要。

在我看来,FROM子句是我决定哪些列需要在我的SELECT子句工作的行。 这是一个业务规则expression的地方,将带到计算所需的同一行。 业务规则可以是具有发票的客户,从而产生包括客户责任的发票行。 它也可以是与客户相同的邮政编码的场所,从而产生一系列相互靠近的场所和客户。

这是我在结果集中的行的中心位置。 毕竟,我们仅仅是在RDBMS中显示一个列表的隐喻,每个列表都有一个主题(实体),每一行都是实体的一个实例。 如果理解行中心,则理解结果集的实体。

WHERE子句在from子句中定义的行之后在概念上执行,可以select不需要的行(或包括所需的行),以便SELECT子句处理。

因为连接逻辑可以在FROM子句和WHERE子句中表示,并且因为子句存在可以分割和征服复杂的逻辑,所以我select在FROM子句中放入涉及列中的值的连接逻辑,因为这基本上expression了一个业务由列中的匹配值支持的规则。

即我不会写这样的WHERE子句:

  WHERE Column1 = Column2 

我将这样放在FROM子句中:

  ON Column1 = Column2 

同样,如果要将列与外部值(可能或不可能在列中的值)进行比较,例如将邮政编码与特定邮政编码进行比较,我将把它放在WHERE子句中,因为我实际上是在说我只想要这样的行。

即我不会写这样的FROM子句:

  ON PostCode = '1234' 

我将这样放在WHERE子句中:

  WHERE PostCode = '1234' 

ANSI语法确实不会在适当的子句(ON或WHERE)中强制执行谓词放置,也不强制ON子句与相邻表引用的相关性。 开发人员可以自由地写这样的混乱

 SELECT C.FullName, C.CustomerCode, O.OrderDate, O.OrderTotal, OD.ExtendedShippingNotes FROM Customer C CROSS JOIN Order O INNER JOIN OrderDetail OD ON C.CustomerID = O.CustomerID AND C.CustomerStatus = 'Preferred' AND O.OrderTotal > 1000.0 WHERE O.OrderID = OD.OrderID; 

说到“将生成ANSI-92”的查询工具,我在这里评论,因为它产生的

 SELECT 1 FROM DEPARTMENTS C JOIN EMPLOYEES A JOIN JOBS B ON C.DEPARTMENT_ID = A.DEPARTMENT_ID ON A.JOB_ID = B.JOB_ID 

传统的“限制 – 项目 – 笛卡尔积”的唯一语法是外连接。 这个操作比较复杂,因为它不是联想的(与自身和普通的联接)。 至less,必须明智地用外连接加括号。 然而,这是一个奇特的操作; 如果你经常使用它,我build议使用关系数据库类。