Oracle表連接方式總結

目錄

一、簡介

二、 SORT MERGE JOIN(排序-合併連接)

三、NESTED LOOPS(嵌套循環)

四、HASH JOIN(哈希連接)

五、CARTESIAN PRODUCT(笛卡爾積)

六、參考資料


一、簡介

Oracle中主要有下面四種表連接方式:

  1. SORT MERGE JOIN(排序-合併連接);
  2. NESTED LOOPS(嵌套循環);
  3. HASH JOIN(哈希連接);
  4. CARTESIAN PRODUCT(笛卡爾積);

Oracle中,通過JOIN關鍵字進行表連接操作,一次只能連接兩張表,JOIN 操作的各步驟一般是串行的(在讀取做連接的兩張表的數據時可以並行讀取)。

需要說明兩個重要的概念:驅動表與匹配表。注意這些概念只存在於NESTED LOOPS(嵌套循環)與 HASH JOIN(哈希連接)兩種表連接方式中。

  • 驅動表(Driving Table):

表連接時首先存取的表,又稱外層表(Outer Table),可以簡單理解爲查詢的主表;

注意:如果驅動表返回的數據行數過多,必須會影響查詢效率,所以我們一般選擇小表(查詢結果返回較少行數的表) 作爲驅動表。

  • 匹配表(Probed Table):

表連接時後面存取的表,又稱爲內層表(Inner Table),也叫被驅動表,可以簡單理解爲查詢的副表;

從驅動表獲取一行具體數據後,會到該表中尋找符合連接條件的行。故該表一般爲大表(查詢結果返回較多行數的表)。

下面通過一些示例對每一種表連接方式進行詳解。

二、 SORT MERGE JOIN(排序-合併連接)

內部連接過程:

  1. 第一步:生成驅動表(主表)需要的數據,按照連接操作關聯列對這些數據進行排序;
  2. 第二步:生成匹配表(附表)需要的數據,按照與上面一步中對應的連接操作關聯列對數據進行排序;
  3. 第三步:兩邊已排序的行放在一起執行合併操作(對兩邊的數據集進行掃描並判斷是否連接);

示例:

explain plan for select * from zhxg_zhcp_cpjgb t1
join zhxg_xsxx_xsjbxx t2
on t1.xsid > t2.PKID;
select * from table(dbms_xplan.display);

執行計劃:

通過上述執行計劃,可見查詢使用到了排序-合併連接方式。

注意事項:排序-合併連接的表無驅動順序,兩個表是對等的,哪個表在前面都可以,可以考慮在操作關聯列上建立索引讓其能預先排好序,連接速度可大大提高。排序合併連接其實很耗費資源,因爲要對2個表/結果集進行排序,所以一般情況下,CBO是不會選擇走SORT MERGE JOIN的。

應用場景:當結果集已經排過序;

適用的連接條件有: <、<=、=、>、>=

不適用的連接條件有: <> 、like

三、NESTED LOOPS(嵌套循環)

內部連接過程:

  • a) 第一步:取出主表(驅動表)的第一行數據,遍歷副表(匹配表)的所有行並檢查是否有匹配的,取出匹配的行放入結果集中;
  • b) 取出主表(驅動表)的第二行數據,遍歷副表(匹配表)的所有行並檢查是否有匹配的,取出匹配的行放入結果集中;
  • c) 若主表(驅動表)中返回了 N 行數據,則副表(匹配表)也相應的會被全表遍歷 N 次;

示例:

zhxg_zhcp_cpjgb數據表的記錄數爲100多條;

zhxg_xsxx_xsjbxx數據表的記錄數爲6000多條;

下面先以記錄數較少的zhxg_zhcp_cpjgb作爲驅動表進行測試,觀察執行計劃。

explain plan for
select /*+ leading(t1) use_nl(t2) */
 *
  from zhxg_zhcp_cpjgb t1
  join zhxg_xsxx_xsjbxx t2
    on t1.xsid = t2.PKID;
select * from table(dbms_xplan.display);

執行計劃:

下面以記錄數較多的zhxg_xsxx_xsjbxx作爲驅動表進行測試,觀察執行計劃。

示例:

explain plan for
select /*+ leading(t2) use_nl(t1) */
 *
  from zhxg_zhcp_cpjgb t1
  join zhxg_xsxx_xsjbxx t2
    on t1.xsid = t2.PKID;
select * from table(dbms_xplan.display);

執行計劃:

可見,這裏以zhxg_xsxx_xsjbxx作爲驅動表測試的話,可能是因爲zhxg_xsxx_xsjbxx表pkid是主鍵,所以這裏顯示的並不是嵌套循環,而是下面我們即將介紹的哈希連接方式。

注意事項:

因爲主表(驅動表)的每一行都會去匹配 副表(匹配表)的所有行,所以當主表(驅動表)返回的行數儘可能少並且能高效訪問副表(匹配表)(如建立適當的索引)時,效率較高。應儘可能使用限制條件(Where過濾條件)使驅動表返回的行數儘可能少,同時在匹配表的連接操作關聯列上建立唯一索引(UNIQUE INDEX)或是選擇性較好的非唯一索引,此時嵌套循環連接的執行效率會變得很高。若驅動表返回的行數較多,即使匹配表連接操作關聯列上存在索引,連接效率也不會很高。

小總結:

  1. 嵌套循環有驅動表和被驅動表的概念,驅動順序不同執行計劃差異非常大;
  2. 驅動表只被訪問一次,被驅動表被訪問多次。嵌套循環訪問表的次數直接受驅動表的返回記錄數的影響。因此應當讓實際返回記錄數(A-Rows)小的表作爲驅動表,返回記錄數大的表作爲被驅動表;
  3. 在驅動表的查詢條件上建立索引可以改善查詢效率;
  4. 在連接條件上建立索引也可以改善查詢效率;
  5. 在被驅動表查詢條件建立索引對查詢效率的影響要視情況而定,不一定帶來好處;

四、HASH JOIN(哈希連接)

內部連接過程:

  • a) 取出主表(驅動表)的數據集,然後將其構建成內存中的一個 Hash Table(Hash函數的Hash KEY就是連接操作關聯列),創建Hash位圖(bitmap);
  • b) 取出副表(匹配表)的數據集,對其中的每一條數據的連接操作關聯列使用相同的Hash函數並找到對應的 a) 裏的數據在 Hash Table 中的位置,在該位置上檢查能否找到匹配的數據;

示例:

explain plan for select /*+ leading(t1) use_hash(t2)*/
 *
  from zhxg_zhcp_cpjgb t1
  join zhxg_xsxx_xsjbxx t2
    on t1.xsid = t2.pkid;
    
select * from table(dbms_xplan.display);

執行計劃:

小總結:

  1. 驅動表和被驅動表都是最多隻被訪問一次;
  2. 哈希連接的表有驅動順序;
  3. 哈希連接不適用於的連接條件是:不等於<>,大於>,小於<,小於等於<=,大於等於>=,like;

五、CARTESIAN PRODUCT(笛卡爾積)

當兩個數據表做連接,但是它們之間沒有關聯條件時,就會在兩個row source中做笛卡兒乘積,這通常由編寫代碼疏漏造成(即程序員忘了寫關聯條件)。笛卡爾乘積是一個表的每一行依次與另一個表中的所有行匹配。在特殊情況下我們可以使用笛卡兒乘積,如在星形連接中,除此之外,我們要儘量使用笛卡兒乘積,否則,查詢效率會非常慢。

假如表t1有n行,t2表有m行,笛卡爾乘積的結果就是得到n * m行結果。

explain plan for select /*+ leading(t1) use_hash(t2)*/
 *
  from zhxg_zhcp_cpjgb t1,    --忘記寫關聯關係
   zhxg_xsxx_xsjbxx t2;
select *
  from table(dbms_xplan.display);

執行計劃:

觀察上面的執行計劃,CARTESIAN關鍵字指出了在2個表之間做笛卡爾乘積。想一下,如果兩個表的數據量都非常大,那麼查詢效率可想而知。

六、參考資料

https://blog.csdn.net/waterxcfg304/article/details/25873265

https://blog.csdn.net/biww620/article/details/73477435/

https://www.cnblogs.com/Dreamer-1/p/6076440.html

https://blog.csdn.net/waterxcfg304/article/details/25872505

https://www.iteye.com/blog/keepwork-1949520

http://blog.itpub.net/28536251/viewspace-2140365/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章