1. 程式人生 > >oracle 表連線方式: nested loop 巢狀迴圈和Hash Join的比較

oracle 表連線方式: nested loop 巢狀迴圈和Hash Join的比較

一、建立兩張實驗用表:wireless_site.merchant和wireless_site.bb

SQL> select count(*) from wireless_site.merchant;

  COUNT(*) ----------      14005

SQL>

SQL> select count(*) from wireless_site.clickthroughrate;

  COUNT(*) ----------    2384026

SQL> create table wireless_site.bb as select * from wireless_site.clickthroughrate;

Table created.

SQL>  SQL> select count(*) from wireless_site.bb;

  COUNT(*) ----------    2384026

SQL>

二、執行SQL語句並檢視sql語句的真實執行計劃:

SQL> alter session set statistics_level=all;

Session altered.

SQL> 

2.1、首先檢視Hash Join的執行計劃:

執行SQL語句:select  * from wireless_site.merchant,wireless_site.bb where bb.recordtype = merchant.merchantid and merchant.merchantid like '%3210%';

等待SQL語句執行完畢,然後再使用這條SQL語句:select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));檢視真實執行計劃:

由以上執行計劃可以看出:

1、HASH JOIN的驅動表為BB,掃描方式為全表掃描,執行了1次,實際返回了1658行

2、HASH JOIN的被驅動表為MERCHANT,掃描方式為全表掃描,執行了1次,實際返回了12行

3、需要注意的是:HASH JOIN的驅動表被被驅動表都會被掃描一次,而nested loop則是驅動表掃描一次,被驅動表被掃描N次(具體N的值是根據驅動表返回的行數來決定的。)

2.2、接著使用HINT的方式讓優化器強制走nested loop(使用wireless_site.merchant作為驅動表)

執行SQL語句:select /*+ leading(merchant) use_nl(bb) */ * from wireless_site.merchant,wireless_site.bb where bb.recordtype = merchant.merchantid and merchant.merchantid like '%3210%';

等待SQL語句執行完畢,然後再使用這條SQL語句:select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));檢視真實執行計劃:

此時,wireless_site.merchant作為驅動表,加上過濾條件filter後,實際返回行數為:

由以上執行計劃可以看出:

1、巢狀迴圈的驅動表為merchant,採用的掃描方式為全表掃描,執行了1次,返回了12行

2、巢狀迴圈的被驅動表為bb,採用的掃描方式是全表掃描,執行了12次,實際返回了1658行

2.3、然後再使用HINT的方式讓優化器強制走nested loop(使用wireless_site.bb作為驅動表)

執行SQL語句:select /*+ leading(bb) use_nl(merchant) */ * from wireless_site.merchant,wireless_site.bb where bb.recordtype = merchant.merchantid and merchant.merchantid like '%3210%'; 等待SQL語句執行完畢,然後再使用這條SQL語句:select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));檢視真實執行計劃:

此時,wireless_site.bb作為驅動表,加上過濾條件filter後,實際返回行數為:

由以上執行計劃可以看出:

1、表BB作為驅動表,掃描方式是全表掃描,實際返回行數為1658

2、表merchant作為被驅動表,採用的掃描方式為索引唯一掃描,執行了1658次,返回了1658行

3、被驅動表merchant索引掃描完成後,通過rowid回表讀數執行了1658次,實際返回了1658行

2.4、接下來在wireless_site.bb表中的recordtype列上建立索引

SQL> create index wireless_site.bb_idx on wireless_site.bb(recordtype);

Index created.

SQL>

接著使用HINT的方式讓優化器強制走nested loop(使用wireless_site.merchant作為驅動表):

執行SQL語句:select /*+ leading(merchant) use_nl(bb) */ * from wireless_site.merchant,wireless_site.bb where bb.recordtype = merchant.merchantid and merchant.merchantid like '%3210%';

等待SQL語句執行完畢,然後再使用這條SQL語句:select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));檢視真實執行計劃:

由執行計劃可以看出:

1、merchant作為驅動表,採用的是全表掃描的方式,實際返回行數為12

2、被驅動表BB的索引採用的是Index Range Scan的方式,實際返回行數為1658,共執行了12次

3、被驅動表BB索引被訪問了12次,每次掃描完索引後又根據rowid回表讀數(TABLE ACCESS BY INDEX ROWID),這樣BB表就被訪問了1658次

對比之前沒有在wireless_site.bb表中的recordtype列上建立索引時的執行計劃可以看出,建立索引後SQL花費不到1s的時間就可以出結果;沒有建立索引時,需要花費1分32秒左右。