2009-07-21 85 views
3

在一些项目中找到的遗留代码中进行重构。这是针对MSSQL的。问题是,我无法理解为什么我们要使用混合的左右连接并将一些连接条件整理在一起。混合左右连接?为什么?

我的问题是这样的:这不是在某些地方创建隐式内部联接而是在其他地方隐式完全联接?

我,几乎任何东西都可以使用被写入学校刚刚离开(和内/全)或恰到好处(和内/全),但是那是因为我喜欢让事情变得简单,其中可能的。

顺便说一句,我们把所有这些东西对Oracle数据库的工作一样,所以也许有与奥拉工作方式不同的一些优化规则?

举例来说,这里是从查询的一个组成部分:

 FROM Table1 
     RIGHT OUTER JOIN Table2 
      ON Table1.T2FK = Table2.T2PK 
     LEFT OUTER JOIN Table3 
     RIGHT OUTER JOIN Table4 
     LEFT OUTER JOIN Table5 
      ON Table4.T3FK = Table5.T3FK 
       AND Table4.T2FK = Table5.T2FK 
     LEFT OUTER JOIN Table6 
     RIGHT OUTER JOIN Table7 
      ON Table6.T6PK = Table7.T6FK 
     LEFT OUTER JOIN Table8 
     RIGHT OUTER JOIN Table9 
      ON Table8.T8PK= Table9.T8FK 
      ON Table7.T9FK= Table9.T9PK 
      ON Table4.T7FK= Table7.T7PK 
      ON Table3.T3PK= Table4.T3PK 
     RIGHT OUTER JOIN (SELECT * 
          FROM  TableA 
          WHERE (TableA.PK = @PK) 
            AND (TableA.Date BETWEEN @StartDate 
                    AND  @EndDate) 
         ) Table10 
      ON Table4.T4PK= Table10.T4FK 
      ON Table2.T2PK = Table4.T2PK 
+0

我不得不承认这让我生病看看!通过所有手段转换为所有左连接。 – HLGEM 2009-07-21 21:51:48

+1

我只是吐在我的嘴里 – dotjoe 2009-07-21 22:04:46

+0

我很抱歉将所有的表名转换为TableX。我有一个预感,这是由一个仍然在这里工作的人写的,我不确定她是否读取了stackoverflow,虽然从你的评论中判断你是多么的无情,但我对此表示怀疑。 – Beta033 2009-07-21 22:35:25

回答

4

我要做的一件事就是确保你知道你在做这件事之前会期待什么结果。不想“修复”它并返回不同的结果。虽然诚实地说,对于设计不佳的查询,我不确定您现在是否确实得到了正确的结果。

对我来说,这看起来像是某人长期以来可能会做的事情,甚至可能最初是从内部联接开始的,意识到他们不会工作并更改为外部联接,但不想打扰更改查询中引用的表的顺序。

特别关注到我要维护的目的是把ON子句旁边的表格要加入,以及将所有连接至左连接,而不是混合左,右连接。将表4和表3的ON子句放在表9旁边对我来说毫无意义,并且应该对查询实际返回的内容造成混淆。您可能还需要更改连接的顺序以转换为所有左连接。就我个人而言,我更喜欢从其他人加入的主桌开始(似乎是桌2),然后从那里开始减少食物链。

0

我可能失去了一些东西,但左,右连接是命令的源表写在之间唯一的区别,所以有多个LEFT连接或多个RIGHT连接与混合搭配没有什么不同。与所有LEFT/RIGHT相比,FULL OUTER的等同可以轻松实现,而不是混合,n'est pas?

1

它也许可以被转换成使用所有LEFT联接:我会寻找并在每个RIGHT是所有现有的左派上述移动右边的表,那么你可能能够然后把每RIGHT加入左连接。我不确定你会在幕后获得任何FULL连接 - 如果查询看起来像这样,它可能是这个特定查询的一个怪癖,而不是SQL Server的“规则”:你提供的查询确实似乎在以一种相当混乱的方式混合起来。

至于Oracle优化 - 这当然是可能的。甲骨文本人没有经验,但是对在这方面有丰富知识的朋友说,甲骨文(不知道是什么版本)对于谓词的顺序非常挑剔。例如,对于SQL Server,您可以编写自己的方式子句,以便列以任意顺序使用,并且索引将被使用,但对于Oracle,您最终必须按索引中出现的顺序指定列,以获得最佳性能与索引。如前所述 - 不知道新甲骨文的情况是否如此,但是老一代(显然)就是这种情况。

这是否解释了这个特殊的结构,我不能说。如果多年来发生了变化,那么它可能只是简化为最优代码,而清理则是它所要求的。

0

我们在相同的查询中有一些LEFT OUTER JOIN s和RIGHT OUTER JOIN s。通常,这种查询很大,已经存在了很长时间,可能写得很差,而且很少进行维护。我假设RIGHT OUTER JOIN是作为一种维护查询的手段而引入的,而不会在重构查询时显着地避免不可避免的风险。

我认为大多数SQL编码器最容易使用全部LEFT OUTER JOIN s,可能是因为FROM子句是从左向右以英文方式读取的。

我用一个RIGHT OUTER JOIN编写基于现有查询的新查询时,当自己是唯一的时间(无需推倒重来),我需要一个INNER JOIN更改为OUTER JOIN。而不是改变FROM条款中的JOIN的顺序,只是为了能够使用LEFT OUTER JOIN而不是使用RIGHT OUTER JOIN,这不会影响我。虽然这很少见。如果原始查询有LEFT OUTER JOIN s,那么我最终会混合使用LEFT - 和RIGHT OUTER JOIN s,这再次不会影响到我。尽管如此,还没有发生在我身上。

注意,对于SQL产品,例如不支持FULL OUTER JOIN Jet数据库引擎,一个解决办法是UNION一个LEFT OUTER JOIN并且在相同的查询RIGHT OUTER JOIN

1

LEFTRIGHT连接是纯语法糖。

任何LEFT JOIN仅仅通过切换集合就可以变换成RIGHT JOIN

9iOracle采用这种结构:

WHERE table1.col = table2.col(+) 

MySQL,有:

WHERE table1.col(+) = table2.col 

(+)这里表示的空列,并LEFTRIGHT联接可以仅仅通过交换来模拟不是FULL OUTER JOIN,它需要被仿真。

通常游戏是做这样:

SELECT * 
FROM table1 
LEFT JOIN 
     table2 
ON  table1.col = table2.col 
UNION ALL 
SELECT * 
FROM table1 
RIGHT JOIN 
     table2 
ON  table1.col = table2.col 
WHERE table1.col IS NULL 

,这是更方便地复制JOINRIGHT取代LEFT,比换表。

请注意,在SQL Server计划中,Hash Left Semi JoinHash Right Semi Join是不同的运算符。

对于这样的查询:

SELECT * 
FROM table1 
WHERE table1.col IN 
     (
     SELECT col 
     FROM table2 
     ) 

Hash Match (Left Semi Join)散列table1,并从哈希表中的运行时匹配的元素(以使它们不能匹配多于一个时间)。

Hash Match (Right Semi Join)散列table2并在构建它时从哈希表中删除重复的元素。

0

底线是这是格式非常差的SQL语句,应该重写。许多ON子句远离它们的JOIN语句,我不确定它甚至是有效的SQL。

为了清晰起见,我将使用所有LEFT JOINS(而不是RIGHT)重写查询,并在其对应的JOIN子句下找到使用语句。否则,这是一个列车残骸,混淆了查询的目的,使得在未来的修改过程中出现错误的可能性更大。

没有这个创建隐含内 联接在一些地方和隐含的全 加入别人?

也许你是假设,因为你没有看到ON子句对于一些连接,例如RIGHT OUTER JOIN Table4,但它位于楼下,ON Table4.T7FK= Table7.T7PK。我没有看到任何隐含的内部联接,如果存在像WHERE Table3.T3PK is not null这样的WHERE子句可能会发生。

事实上,你问这样的问题是对查询不透明性的证明。

0

要回答尚未回答的此问题的另一部分,此查询的格式非常奇怪的原因是它可能使用SQL Management Studio中的查询设计器构建。放弃是在提到表格后发生多行的组合ON子句。本质上来说,表格被添加到构建查询窗口中,并且即使事物连接的方式会支持移动表格,也可以保持所有连接朝某个方向。