2013-07-26 24 views
1

我嘗試瞭解如何使用大量JOIN子句更正寫入大型查詢。 這個查詢具有相同的性能嗎?如何使用LEFT JOIN編寫查詢以獲得更高性能

/*Sql 1*/ 
SELECT G.ID, T1.QUANTITY, T2.QUANTITY 
FROM GOODS G 
LEFT JOIN 
/*First subquery*/ 
(SELECT SUM(QUANTITY) QUANTITY, GOOD_ID 
FROM MY_TABLE_1 
GROUP BY GOOD_ID 
) T1 ON G.ID = T1.GOOD_ID 
LEFT JOIN 
/*Second subquery*/ 
(SELECT SUM(QUANTITY) QUANTITY, GOOD_ID 
GROUP BY GOOD_ID 
FROM MY_TABLE_2 
) T2 ON G.ID = T2.GOOD_ID 
/*and so on....Next same subqueries*/ 
WHERE G.ID IN (1, 2, 3, 4); 

在相同的下一個查詢的WHERE子句中的所有連接子查詢和外LEFT JOIN子句在內CLAUSE更換設置。這是一個好的解決方案嗎?還是oracle優化器自動做出這樣的事情?

/*Sql 2*/ 
SELECT G.ID, T1.QUANTITY, T2.QUANTITY 
FROM GOODS G 
INNER JOIN 
/*First subquery*/ 
(SELECT SUM(QUANTITY) QUANTITY, GOOD_ID 
FROM GOODS G 
LEFT JOIN MY_TABLE_1 M ON M.GOOD_ID = G.ID 
WHERE G.ID IN (1, 2, 3, 4); 
GROUP BY GOOD_ID 
) T1 ON G.ID = T1.GOOD_ID 
INNER JOIN 
/*Second subquery*/ 
(SELECT SUM(QUANTITY) QUANTITY, GOOD_ID 
FROM GOODS G 
LEFT JOIN MY_TABLE_2 M ON M.GOOD_ID = G.ID 
WHERE G.ID IN (1, 2, 3, 4); 
GROUP BY GOOD_ID 
) T2 ON G.ID = T2.GOOD_ID 
/*and so on....Next same subqueries*/ 
WHERE G.ID IN (1, 2, 3, 4); 

回答

1

查詢性能將取決於很多東西,包括:

  • 表的相對大小涉及
  • 存在或不存在索引覆蓋連接列和過濾準則的
  • 的數據庫中表格統計的貨幣
  • 查詢寫入的方式。

這是絕對不真實的 OUTER連接比INNER連接(雖然可能有一些查詢能夠爲這是真的)快。所以,基於這個理論,嘗試轉換查詢以使用更多的OUTER連接並不是很好的利用你的時間。

有寫在性能優化整本書,但一些一般規則包括

  • 在您的查詢,做表連接和WHERE中最選擇性至少選擇性的順序(即,如果你有一個標準加入後會將返回集的大小減少80%,並將其放在查詢頂部附近)。優化器理論上應該能夠根據表統計信息對這些標準進行重新排序,但是我發現給它額外的幫助有時會產生差異。

  • 學習閱讀SQL執行計劃。他們會告訴你究竟是數據庫如何處理您的請求,並且您可以瞭解它是否錯過並編制索引(或者數據庫是否缺少可能對性能有用的索引),何時能夠使用範圍,直接索引命中,或全表掃描等。

  • 有時用非常長時間運行的查詢將一些初步結果轉移到臨時表中,然後對錶進行適當索引,然後對該表執行其餘的查詢。特別是當你需要加入或過濾一些計算標準時,如果你能找到一些策略,用更直接的標準預先過濾你的結果的一部分,那麼這些標準將強制大表的表掃描。

+0

你寫之前,「這是絕對不真實OUTER連接速度比INNER連接速度快「,然後」..嘗試轉換查詢以使用更多的OUTER連接..「。那麼什麼是好的做法 - 使用LEFT OUTER JOIN還是嘗試在INNER JOIN上替換它? – user1881712

+0

我同意內部連接要好得多。外連接意味着Oracle必須在每一行上創建行。沒有任何術語的「JOIN」意味着「INNER JOIN」。只有在需要時才使用OUTER JOIN,因爲如果沒有匹配的數據,則需要空白值。否則,請使用INNER JOIN – AngelWarrior

+0

使用OUTER和INNER聯接應該幾乎完全取決於所討論的表之間的關係,以及您試圖從這種關係中提取的數據類型。我通常對INNER連接有一點偏好,因爲它們可能會導致較少的中間IO,但是您必須根據自己的經驗和對數據的理解來指導您。 – Curt

0

爲了獲得最佳效果,儘可能快地減少第一張表,以便oracle不會創建大量額外的行來丟棄。然後在子查詢中添加該過濾器,而不是在完成之後。我會嘗試:

SELECT G.ID, T1.QUANTITY, T2.QUANTITY 
    FROM GOODS G 
    JOIN DUAL ON G.ID IN (1, 2, 3, 4) 
    LEFT JOIN (SELECT SUM(QUANTITY) AS QUANTITY, GOOD_ID 
      FROM MY_TABLE_1 T 
     GROUP BY GOOD_ID 
     ) T1 ON T1.GOOD_ID = G.ID 
    LEFT JOIN (SELECT SUM(QUANTITY) AS QUANTITY, GOOD_ID 
      FROM MY_TABLE_2 T 
     GROUP BY GOOD_ID 
     ) T2 ON T2.GOOD_ID = G.ID 
+0

我不明白什麼使用 JOIN DUAL ON G.ID IN(1,2,3,4) 和子查詢中的條件「WHERE T.GOOD_ID = G.ID」給出錯誤 – user1881712

+0

JOIN DUAL ON G.ID IN(1,2,3,4)與末尾的WHERE子句相同。這樣做,如果你在GOODS中有1000行其他行,那麼Oracle不需要對所有GOODS的行進行行連接,這些行只會被丟棄。我不確定爲什麼子查詢中的where子句有錯誤 - 你可以刪除它。主要的一點是先做連接對偶,然後才能繼續獲得四個ID。 – AngelWarrior

+0

好吧,我瞭解DUAL的使用。謝謝 – user1881712

0

優化器負責大部分的事情。 你應該做以下 嘗試加入的主鍵 如果不可能再提供涉及使用加入 如果可能的篩選結果列的索引的where子句,以減少行源表格加入