我在~7000行T-SQL存储过程中有我的业务逻辑,其中大多数都有下一个JOIN语法:
SELECT A.A, B.B, C.C
FROM aaa AS A, bbb AS B, ccc AS C
WHERE
A.B = B.ID
AND B.C = C.ID
AND C.ID = @param
如果我用这个替换这样的查询,我会获得性能增长:
SELECT A.A, B.B, C.C
FROM aaa AS A
JOIN bbb AS B
ON A.B = B.ID
JOIN ccc AS C
ON B.C = C.ID
AND C.ID = @param
或者他们是一样的?
答案 0 :(得分:74)
两个查询是相同的,除了第二个是ANSI-92 SQL语法,第一个是没有包含join子句的旧SQL语法。它们应该生成完全相同的内部查询计划,尽管您可能需要检查。
出于几个原因,您应该使用ANSI-92语法
我自己在一段时间内抵制ANSI-92,因为旧语法略有概念上的优势,因为它更容易设想SQL作为所有表的大规模笛卡尔连接,然后是过滤操作 - 一种心理技巧可以用于掌握SQL查询正在执行的操作。然而,几年前我决定我需要与时俱进,经过相对较短的调整期后,我现在非常喜欢它 - 主要是因为上面提到的第一个原因。唯一一个应该偏离ANSI-92语法的地方,或者更确切地说不使用该选项的地方是自然连接,这是隐含的危险。
答案 1 :(得分:4)
第二个结构在SQL社区中称为“无限连接语法”。第一个构造AFAIK没有广泛接受的名称,所以我们称之为'旧式'内连接语法。
通常的论点是这样的:
'传统'语法的优点:
谓词在WHERE
子句中被物理地组合在一起
无论什么顺序使得查询一般,特别是n-ary关系,更容易阅读和理解(不完整语法的ON
子句可以展开谓词,所以你必须寻找一个表或列的外观在视距上。)
'传统'语法的缺点:省略其中一个'join'谓词时没有解析错误,结果是笛卡尔积(在混合语法中称为CROSS JOIN
)并且出现这样的错误检测和调试可能很棘手。此外,'join'谓词和'过滤'谓词在WHERE
子句中被物理地组合在一起,这可能导致它们彼此混淆。
答案 2 :(得分:3)
执行两者并检查他们的查询计划。他们应相等。
答案 3 :(得分:3)
两个查询 相等 - 第一个使用非ANSI JOIN语法,第二个是ANSI JOIN语法。我建议坚持使用ANSI JOIN语法。
是的,当您加入的表可能不包含任何匹配记录时,LEFT OUTER JOIN(其中,btw也是ANSI JOIN语法)是您想要使用的。
答案 4 :(得分:3)
好的,他们执行相同的操作。这是同意的。 与许多人不同,我使用较旧的惯例。 SQL-92“更容易理解”是值得商榷的。编写了40年的编程语言(gulp)我知道“易于阅读”首先在任何其他约定之前开始,具有“视敏度”(这里误用术语,但这是我可以使用的最好的词组)。 在阅读SQL时,您首先关心的是涉及哪些表,然后是哪个表(大多数)定义了粒度。然后,您关心数据的相关约束,然后选择所选的属性。虽然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的第一个表成为连接约束,并让特定的紧密约束浮动到底部。 为数据库中的所有表选择3个字符别名,并使用别名EVEREWHERE引用该表。您应该使用该别名作为该表上(许多)索引的前缀。 6 1/2的打打,对吗?也许。但即使您使用的是ANSI-92惯例(正如我所拥有并在案例中将继续这样做),使用视敏度原则,垂直对齐让您的大脑避开您想要看到的地方,并轻松避开事物(特别是噪音词)你不需要。
答案 5 :(得分:1)
在我看来,FROM子句是我决定行中需要哪些列来处理SELECT子句的地方。这是表达业务规则的地方,它将带来计算所需的同一行。业务规则可以是具有发票的客户,从而产生包括客户负责的发票行。它也可以是与客户相同的邮政编码中的场所,从而产生一个靠近的场地和客户列表。
这是我计算结果集中行的中心的地方。毕竟,我们只是简单地展示了RDBMS中列表的隐喻,每个列表都有一个主题(实体),每一行都是实体的一个实例。如果理解行中心性,则理解结果集的实体。
WHERE子句在概念上在from子句中定义行之后执行,它会剔除SELECT子句不需要的行(或包含所需的行)。
因为连接逻辑可以在FROM子句和WHERE子句中表示,并且因为存在用于划分和征服复杂逻辑的子句,所以我选择将包含值的连接逻辑放在FROM子句的列中,因为这基本上是表达匹配列中值的业务规则。
即。我不会写这样的WHERE子句:
WHERE Column1 = Column2
我会把它放在FROM子句中,如下所示:
ON Column1 = Column2
同样,如果要将列与外部值(列中可能存在或不存在的值)进行比较,例如将邮政编码与特定邮政编码进行比较,我会将其放在WHERE子句中,因为我实质上是在说我只想要这样的行。
即。我不会写这样的FROM子句:
ON PostCode = '1234'
我会把它放在WHERE子句中,如下所示:
WHERE PostCode = '1234'
答案 6 :(得分:0)
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
唯一逃避传统“restrict-project-cartesian product”的语法是外连接。此操作更复杂,因为它不是关联的(本身和正常连接)。至少,必须明智地用外连接括起查询。然而,这是一项奇特的行动;如果你经常使用它我建议采用关系数据库类。