多表鏈接的三種方式: HASH JOIN,MERGE JOIN,NESTED LOOPhtml
NESTED LOOP: 嵌套循環鏈接,適用於內表數據量較小時。外表返回的每一行都要在內表中檢索找到與它匹配的行,所以整個查詢返回的結果集不能太大(大於1 萬不適合),並且在內表的鏈接字段上最好創建索引。sql
HASH JOIN: 哈希/散列鏈接,適用於小表(驅動表)連大表,且較小的表徹底能夠放於內存中的狀況。可是在表很大的狀況下並不能徹底放入內存,這時優化器會將它分割成若干不一樣的分區,不能放入內存的部分就把該分區寫入磁盤的臨時段,此時要有較大的臨時段從而儘可能提升I/O 的性能。架構
SORT MERGE JOIN: 排序合併鏈接,適用於沒有索引且數據已經排序、不等價關聯等狀況。一般狀況下散列鏈接的效果都比排序合併鏈接要好,然而若是行源已經被排過序,在執行排序合併鏈接時不須要再排序了,這時排序合併鏈接的性能會優於散列鏈接。oracle
1、 大表關聯的優化方法 -- hash分區app
參考連接:20億與20億表關聯優化方法(超級大表與超級大表join優化方法)函數
問題:兩個20億大表關聯耗時一天一晚上post
執行的SQL: select * from t1,t2 where t1.object_id=t2.object_id;性能
關聯慢的緣由:單個進程的PGA裝不下大表數據 --> 消耗大量臨時表空間 --> 臨時表來回讀寫優化
優化方法:url
1)開並行,並行hash。 -- 不可行
2)利用MPP架構/HADOOP架構思想:數據分割。
數據分割方法:一個是分區;另一個是分表。本文選用分區。
步驟:
1)建立表P1,P2。在T1的表結構基礎上多加一個字段HASH_VALUE,並且依據HASH_VALUE進行LIST分區。同理,P2。
注意:工做中具體須要多少分區需本身判斷,但P1和P2表的分區必須如出一轍。
CREATE TABLE P1( HASH_VALUE NUMBER, OWNER VARCHAR2(30), OBJECT_NAME VARCHAR2(128), SUBOBJECT_NAME VARCHAR2(30), OBJECT_ID NUMBER, DATA_OBJECT_ID NUMBER, OBJECT_TYPE VARCHAR2(19), CREATED DATE, LAST_DDL_TIME DATE, TIMESTAMP VARCHAR2(19), STATUS VARCHAR2(7), TEMPORARY VARCHAR2(1), GENERATED VARCHAR2(1), SECONDARY VARCHAR2(1), NAMESPACE NUMBER, EDITION_NAME VARCHAR2(30) ) PARTITION BY list(HASH_VALUE) ( partition p0 values (0), partition p1 values (1), partition p2 values (2), partition p3 values (3), partition p4 values (4) )
2)向P1,P2中插入數據。
oracle中的hash分區就是利用的ora_hash函數。
partition by hash(object_id) <=> ora_hash(object_id,4294967295)
ora_hash(列,hash桶) ,hash桶默認是4294967295,可以設置0到4294967295。
ora_hash(object_id,4) 會把object_id的值進行hash運算,而後放到 0,1,2,3,4 這些桶裏面。
delete t1 where object_id is null; commit; delete t2 where object_id is null; commit; insert into p1 select ora_hash(object_id,4), a.* from t1 a; ---工做中用append parallel並行插入 commit; insert into p2 select ora_hash(object_id,4), a.* from t2 a; ---工做中用append parallel並行插入 commit;
3)執行表關聯。
優化後執行時間大約1小時。可將該過程整理爲存儲過程。
select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=0 and p2.hash_value=0; select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=1 and p2.hash_value=1; select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=2 and p2.hash_value=2; select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=3 and p2.hash_value=3; select * from p1,p2 where p1.object_id=p2.object_id and p1.hash_value=4 and p2.hash_value=4;
2、小表與大表關聯 -- hash join
參考連接:oracle錶鏈接----->哈希鏈接(Hash Join)
1)執行hash join
select /*+ leading(t1) use_hash(t2)*/ * from t1,t2 where t1.id=t2.t1_id; --可連個表都創建hash, use_hash(t1 t2)
2)查看執行計劃
若是條件成立,驅動表和被驅動表都只被訪問1次(主要看 starts),不然訪問0次。
哈希鏈接中驅動表的選擇很是重要,性能(主要看 A-Time | Buffers | OMem | 1Mem | Used-Mem)差異也大。通常選用結果集較小的表(非數據量)爲驅動表。
-- 查看執行代碼的 sql_id select sql_id, child_number, sql_text from v$sql where sql_text like '%use_hash(t2)%'; -- 查看指定 sql_id 的執行計劃 select * from table(dbms_xplan.display_cursor('036fyatp73h9n',0,'allstats last'));
3)其餘
hash join 不支持不等值鏈接。(執行計劃走的是 NESTED LOOPS JOIN)
explain plan for select /*+ leading(t2) use_hash(t1)*/ * from t1,t2 where t1.id<>t2.t1_id and t1.num=20; select * from table(dbms_xplan.display);
參考連接: