2009-07-21 135 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子句。本質上來說,表格被添加到構建查詢窗口中,並且即使事物連接的方式會支持移動表格,也可以保持所有連接朝某個方向。