程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle教程 >> oracle表連接-----)哈希連接(HashJoin)

oracle表連接-----)哈希連接(HashJoin)

編輯:Oracle教程

哈希連接(HASH JOIN)是一種兩個表在做表連接時主要依靠哈希運算來得到連接結果集的表連接方法。

對於排序合並連接,如果兩個表在施加了目標SQL中指定的謂詞條件後得到的結果集很大而且需要排序,則排序合並連接的執行效率一定不高;而對於嵌套循環連接,如果驅動表所對應的驅動結果集的記錄數很大,即便在被驅動表的連接列上存在索引,此時使用嵌套循環連接的執行效率也會同樣不高。為了解決這個問題,於是ORACLE引進了哈希連接。在ORACLE 10g及其以後的版本中,優化器 (實際上是CBO,因為哈希連接僅適用於CBO)在解析目標SQL的時候是否考慮哈希連接受限於隱含參數_HASH_JOIN_ENABLED,默認值是TRUE.

對於哈希連接的優缺點及適用場景如下:

a,哈希連接不一定會排序,或者說大多數情況下都不需要排序

b,哈希連接的驅動表所對應的連接列的選擇性盡可能好。

c,哈希只能用於CBO,而且只能用於等值連接的條件。(即使是哈希反連接,ORACLE實際上也是將其換成等值連接)。

c,哈希連接很適用小表和大表之間做連接且連接結果集的記錄數較多的情形,特別是小表的選擇性非常好的情況下,這個時候哈希連接的執行時間就可以近似看做和全表掃描個個大表的費用時間相當。

e,當兩個哈希連接的時候,如果在施加了目標SQL中指定的謂詞條件後得到的數據量較小的那個結果集所對應的HASH TABLE能夠完全被容納在內存中(PGA的工作區),此時的哈希連接的執行效率非常高。

oracle表之間的連接之哈希連接(Hash Join),其特點如下:

1,驅動表和被驅動表都是最多只被訪問一次。

2,哈希連接的表有驅動順序。

3,哈希表連接的表無需要排序,但是他在做連接之前做哈希運算的時候,會用到HASH_AREA_SIZE來創建哈希表。

4,哈希連接不適用於的連接條件是:不等於<>,大於>,小於<,小於等於<=,大於等於>=,like。

5,哈希連接索引列在表連接中無特殊要求,與單表情況無異。

下面我來做個實驗來證實如上的結論:

具體的測試基礎表請查看本人Blog 如下鏈接:

oracle表連接之----〉嵌套循環(Nested Loops Join)

測試T2表僅被訪問1次

SQL> select /*+ leading(t1) use_hash(t2)*/ * from t1,t2 where t1.id=t2.t1_id;

此處省略執行的結果記錄集

SQL> select sql_id, child_number, sql_text from v$sql where sql_text like '%use_hash(t2)%';

SQL_ID CHILD_NUMBER SQL_TEXT
------------- ------------ --------------------------------------------------------------------------------
7d64k5stnc3sk 0 select sql_id, child_number, sql_text from v$sql where sql_text like '%use_hash
036fyatp73h9n 0 select /*+ leading(t1) use_hash(t2)*/ * from t1,t2 where t1.id=t2.t1_id

SQL> select * from table(dbms_xplan.display_cursor('036fyatp73h9n',0,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID 036fyatp73h9n, child number 0
-------------------------------------
select /*+ leading(t1) use_hash(t2)*/ * from t1,t2 where t1.id=t2.t1_id
Plan hash value: 1838229974
--------------------------------------------------------------------------------
| Id | Operation | Name | Starts| E-Rows | A-Rows | A-Time | Buff
--------------------------------------------------------------------------------
|* 1 | HASH JOIN | | 1 | 100 | 100 |00:00:00.04 | 1
| 2 | TABLE ACCESS FULL| T1 | 1 | 100 | 100 |00:00:00.01 |
| 3 | TABLE ACCESS FULL| T2 | 1 | 100K| 100K|00:00:00.01 | 1
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."ID"="T2"."T1_ID")
Note

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
-----
- dynamic sampling used for this statement

23 rows selected

從上面的執行計劃可以看出,HASH連接中,驅動表和被驅動表都只會被訪問1次。

下面的實驗來證明驅動表和被驅動表都是被訪問0次。


SQL> select /*+ leading(t1) use_hash(t2)*/ * from t1,t2 where t1.id=t2.t1_id and 1=2;

ID NUM INFORMATION ID T1_ID NUM INFORMATION
---------- ---------- -------------------------------------------------------------------------------- ---------- ---------- ---------- --------------------------------------------------------------------------------
SQL> select sql_id, child_number, sql_text from v$sql where sql_text like '%use_hash(t2)%';

SQL_ID CHILD_NUMBER SQL_TEXT
------------- ------------ --------------------------------------------------------------------------------
7d64k5stnc3sk 0 select sql_id, child_number, sql_text from v$sql where sql_text like '%use_hash
cknub2x1sx8tn 0 select /*+ leading(t1) use_hash(t2)*/ * from t1,t2 where t1.id=t2.t1_id and 1=2
2jhn0mg57v1tz 0 select sql_id, child_number, sql_text from v$sql where sql_text like '%use_hash
036fyatp73h9n 0 select /*+ leading(t1) use_hash(t2)*/ * from t1,t2 where t1.id=t2.t1_id

SQL> select * from table(dbms_xplan.display_cursor('cknub2x1sx8tn',0,'allstats last'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID cknub2x1sx8tn, child number 0
-------------------------------------
select /*+ leading(t1) use_hash(t2)*/ * from t1,t2 where t1.id=t2.t1_id and 1=2
Plan hash value: 487071653
--------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | OM
--------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 0 |00:00:00.01 |
|* 2 | HASH JOIN | | 0 | 100 | 0 |00:00:00.01 | 7
| 3 | TABLE ACCESS FULL| T1 | 0 | 100 | 0 |00:00:00.01 |
| 4 | TABLE ACCESS FULL| T2 | 0 | 100K| 0 |00:00:00.01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(NULL IS NOT NULL)
2 - access("T1"."ID"="T2"."T1_ID")

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement

25 rows selected

通過上面的兩個執行計劃可以得出結論:HASH連接中,驅動表和被驅動表都只會被訪問1次或者0次。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved