use_nl,use_hash,use_merge的3種連線方式驅動與被驅動關係
雜湊連線(HASH JOIN)是一種兩個表在做表連線時主要依靠雜湊運算來得到連線結果集的表連線方法。
對於排序合併連線,如果兩個表在施加了目標SQL中指定的謂詞條件後得到的結果集很大而且需要排序,則排序合併連線的執行效率一定不高;而對於巢狀迴圈連線,如果驅動表所對應的驅動結果集的記錄數很大,即便在被驅動表的連線列上存在索引,此時使用巢狀迴圈連線的執行效率也會同樣不高。為了解決這個問題,於是引進了雜湊連線。在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,雜湊連線索引列在表連線中無特殊要求,與單表情況無異。
************************************************************************************************SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for : Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
點選(此處)摺疊或開啟
-
--use_nl,use_hash,use_merge的3種連線方式驅動與被驅動關係
-
-
一.HASH連線方式
-
-
--建一個小表和一個大一些的表
-
SQL> create table t1 as select * from dba_objects where rownum<11;
-
-
Table created.
-
-
SQL> create table t2 as select * from dba_objects;
-
-
Table created.
-
-
SQL> select count(1) from t1;
-
-
COUNT(1)
-
----------
-
10
-
-
SQL> select count(1) from t2;
-
-
COUNT(1)
-
----------
-
75211
-
-
--試驗HASH,可以看出hash是存在驅動與被驅動關係,驅動表適合於兩表間較小的一個,耗用更少的排序開銷;
-
SQL> select /*+ leading(t2) use_hash(t2,t1) */t1.status,t2.status
-
2 from t1,t2
-
3 where t1.object_id=t2.object_id;
-
-
STATUS STATUS
-
------- -------
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
-
10 rows selected.
-
-
--看到排序區中排序的開銷為3439K;
-
SQL> @allstat
-
-
PLAN_TABLE_OUTPUT
-
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
SQL_ID 315bd4pgdyt86, child number 1
-
-------------------------------------
-
select /*+ leading(t2) use_hash(t2,t1) */t1.status,t2.status from t1,t2
-
where t1.object_id=t2.object_id
-
-
Plan hash value: 2959412835
-
-
-------------------------------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
-
-------------------------------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.08 | 1078 | 1071 | | | |
-
|* 1 | HASH JOIN | | 1 | 10 | 10 |00:00:00.08 | 1078 | 1071 | 3439K| 1573K| 5617K (0)|
-
| 2 | TABLE ACCESS FULL| T2 | 1 | 79628 | 75211 |00:00:00.02 | 1074 | 1071 | | | |
-
| 3 | TABLE ACCESS FULL| T1 | 1 | 10 | 10 |00:00:00.01 | 4 | 0 | | | |
-
-------------------------------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
-
25 rows selected.
-
-
--而T1表為驅動表時,排序的開銷為1206K比上面的3439K小得多;
-
SQL> select /*+ leading(t1) use_hash(t2,t1) */t1.status,t2.status
-
2 from t1,t2
-
3 where t1.object_id=t2.object_id;
-
-
STATUS STATUS
-
------- -------
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
VALID VALID
-
-
10 rows selected.
-
-
SQL> @allstat
-
-
PLAN_TABLE_OUTPUT
-
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
SQL_ID 3zc11bg9gdq31, child number 1
-
-------------------------------------
-
select /*+ leading(t1) use_hash(t2,t1) */t1.status,t2.status from t1,t2
-
where t1.object_id=t2.object_id
-
-
Plan hash value: 1838229974
-
-
-------------------------------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
-
-------------------------------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.08 | 1078 | 1071 | | | |
-
|* 1 | HASH JOIN | | 1 | 10 | 10 |00:00:00.08 | 1078 | 1071 | 1206K| 1206K| 1126K (0)|
-
| 2 | TABLE ACCESS FULL| T1 | 1 | 10 | 10 |00:00:00.01 | 3 | 0 | | | |
-
| 3 | TABLE ACCESS FULL| T2 | 1 | 79628 | 75211 |00:00:00.03 | 1075 | 1071 | | | |
-
-------------------------------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
-
25 rows selected.
-
-
--而ORACLE在預估COST時第一類的COST也是大於第2類,也就是預設O是會採用第2種方式;
-
--第1類的COST為419,而第2類的COST預估為305;
-
SQL> set auto traceonly
-
SP2-0158: unknown SET autocommit option "traceonly"
-
Usage: SET AUTO[COMMIT] { OFF | ON | IMM[EDIATE] | n }
-
SQL> set autot traceonly exp
-
SQL>
-
SQL> select /*+ leading(t2) use_hash(t2,t1) */t1.status,t2.status
-
2 from t1,t2
-
3 where t1.object_id=t2.object_id;
-
-
Execution Plan
-
----------------------------------------------------------
-
Plan hash value: 2959412835
-
-
-----------------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-
-----------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 10 | 360 | | 419 (1)| 00:00:06 |
-
|* 1 | HASH JOIN | | 10 | 360 | 2336K| 419 (1)| 00:00:06 |
-
| 2 | TABLE ACCESS FULL| T2 | 79628 | 1399K| | 301 (1)| 00:00:04 |
-
| 3 | TABLE ACCESS FULL| T1 | 10 | 180 | | 3 (0)| 00:00:01 |
-
-----------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
SQL> select /*+ leading(t1) use_hash(t2,t1) */t1.status,t2.status
-
2 from t1,t2
-
3 where t1.object_id=t2.object_id;
-
-
Execution Plan
-
----------------------------------------------------------
-
Plan hash value: 1838229974
-
-
---------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
---------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 10 | 360 | 305 (1)| 00:00:04 |
-
|* 1 | HASH JOIN | | 10 | 360 | 305 (1)| 00:00:04 |
-
| 2 | TABLE ACCESS FULL| T1 | 10 | 180 | 3 (0)| 00:00:01 |
-
| 3 | TABLE ACCESS FULL| T2 | 79628 | 1399K| 301 (1)| 00:00:04 |
-
---------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
--HASH連線方式預設當然是採用後一種COST較小那類;
-
SQL> select t1.status,t2.status
-
2 from t1,t2
-
3 where t1.object_id=t2.object_id;
-
-
Execution Plan
-
----------------------------------------------------------
-
Plan hash value: 1838229974
-
-
---------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-
---------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 10 | 360 | 305 (1)| 00:00:04 |
-
|* 1 | HASH JOIN | | 10 | 360 | 305 (1)| 00:00:04 |
-
| 2 | TABLE ACCESS FULL| T1 | 10 | 180 | 3 (0)| 00:00:01 |
-
| 3 | TABLE ACCESS FULL| T2 | 79628 | 1399K| 301 (1)| 00:00:04 |
-
---------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
-
二.排序合併連線方式
-
--可以看到無論是哪種表排在前面先執行,其開銷都是一樣的;也就是說明merge方式是不存在驅動與被驅動的區別關係 ;
-
PLAN_TABLE_OUTPUT
-
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
SQL_ID 2yw072zjb9h5b, child number 1
-
-------------------------------------
-
select /*+ leading(t1) use_merge(t2,t1) */t1.status,t2.status from
-
t1,t2 where t1.object_id=t2.object_id
-
-
Plan hash value: 412793182
-
-
--------------------------------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
-
--------------------------------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.06 | 1077 | 1071 | | | |
-
| 1 | MERGE JOIN | | 1 | 10 | 10 |00:00:00.06 | 1077 | 1071 | | | |
-
| 2 | SORT JOIN | | 1 | 10 | 10 |00:00:00.01 | 3 | 0 | 2048 | 2048 | 2048 (0)|
-
| 3 | TABLE ACCESS FULL| T1 | 1 | 10 | 10 |00:00:00.01 | 3 | 0 | | | |
-
|* 4 | SORT JOIN | | 10 | 79628 | 10 |00:00:00.06 | 1074 | 1071 | 2675K| 740K| 2377K (0)|
-
| 5 | TABLE ACCESS FULL| T2 | 1 | 79628 | 75211 |00:00:00.02 | 1074 | 1071 | | | |
-
--------------------------------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
filter("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
-
28 rows selected.
-
-
PLAN_TABLE_OUTPUT
-
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
SQL_ID csjsgn0hh4dr6, child number 1
-
-------------------------------------
-
select /*+ leading(t2) use_merge(t2,t1) */t1.status,t2.status from
-
t1,t2 where t1.object_id=t2.object_id
-
-
Plan hash value: 1792967693
-
-
--------------------------------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
-
--------------------------------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.09 | 1077 | 1071 | | | |
-
| 1 | MERGE JOIN | | 1 | 10 | 10 |00:00:00.09 | 1077 | 1071 | | | |
-
| 2 | SORT JOIN | | 1 | 79628 | 54 |00:00:00.09 | 1074 | 1071 | 2675K| 740K| 2377K (0)|
-
| 3 | TABLE ACCESS FULL| T2 | 1 | 79628 | 75211 |00:00:00.02 | 1074 | 1071 | | | |
-
|* 4 | SORT JOIN | | 54 | 10 | 10 |00:00:00.01 | 3 | 0 | 2048 | 2048 | 2048 (0)|
-
| 5 | TABLE ACCESS FULL| T1 | 1 | 10 | 10 |00:00:00.01 | 3 | 0 | | | |
-
--------------------------------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
filter("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
三.巢狀迴圈連線方式是影響最為明顯的,buffers數相差了10倍之多;
-
-
PLAN_TABLE_OUTPUT
-
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
SQL_ID 35g7vtpc63s04, child number 0
-
-------------------------------------
-
select /*+ leading(t1) use_nl(t2,t1) */t1.status,t2.status from t1,t2
-
where t1.object_id=t2.object_id
-
-
Plan hash value: 1967407726
-
-
----------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-
----------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.11 | 10745 | 10710 |
-
| 1 | NESTED LOOPS | | 1 | 10 | 10 |00:00:00.11 | 10745 | 10710 |
-
| 2 | TABLE ACCESS FULL| T1 | 1 | 10 | 10 |00:00:00.01 | 4 | 0 |
-
|* 3 | TABLE ACCESS FULL| T2 | 10 | 1 | 10 |00:00:00.11 | 10741 | 10710 |
-
----------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
3 - filter("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
PLAN_TABLE_OUTPUT
-
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
SQL_ID 1a5dw45kqph9p, child number 0
-
-------------------------------------
-
select /*+ leading(t2) use_nl(t2,t1) */t1.status,t2.status from t1,t2
-
where t1.object_id=t2.object_id
-
-
Plan hash value: 4016936828
-
-
----------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-
----------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.93 | 226K| 1071 |
-
| 1 | NESTED LOOPS | | 1 | 10 | 10 |00:00:00.93 | 226K| 1071 |
-
| 2 | TABLE ACCESS FULL| T2 | 1 | 79628 | 75211 |00:00:00.06 | 1075 | 1071 |
-
|* 3 | TABLE ACCESS FULL| T1 | 75211 | 1 | 10 |00:00:00.74 | 225K| 0 |
-
----------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
3 - filter("T1"."OBJECT_ID"="T2"."OBJECT_ID")
-
-
Note
-
-----
-
- dynamic sampling used for this statement (level=2)
-
-
-
25 rows selected.
-
-
-
小結:從以上可看出,影響大到小的順序為nl->hash->merge(不影響);
-
應用:日常工作環境中經常可看到,由於nl方式不當而應使用hash的案例,畢竟NL對資料量的大小影響是最為敏感;
-
而ORACLE選擇NL方式並沒有錯,錯就錯在預估值那裡,所以當用explain plan for....,autot等方式看並不能看出問題;
-
當透過running time的統計資訊收集然後select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
-
就會發現真正的原因是預估值與實際值的問題相差過大導致的;
- 在這種情況下執行計劃的繫結是比較實用和有效的;
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29209863/viewspace-2128167/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL的驅動表與被驅動表MySql
- 領域驅動設計與模型驅動設計的關係模型
- MySQL連線查詢驅動表被驅動表以及效能優化MySql優化
- 各種資料庫的jdbc驅動下載及連線方式資料庫JDBC
- 通過驅動建立與MySQL的連線MySql
- redis的php驅動兩種方式RedisPHP
- py連線mysql常用驅動的兩種對比MySql
- 幾種連線資料庫的OLEDB驅動程式資料庫
- Firefox的降級與驅動對應關係Firefox
- IPA加驅動的一種方式,未驗證
- 請教:域驅動設計和模型驅動設計是什麼樣的關係模型
- 資料驅動決策的13種思維方式
- 驅動和應用層的三種通訊方式
- 如何理解自動化測試資料驅動與關鍵字驅動的區別?
- mini2440驅動奇譚——ADC驅動與測試(動態掛載驅動)
- 連線LilyPad之Windows平臺的驅動Windows
- 怎樣通過驅動程式連線到access
- Struts2的屬性驅動與模型驅動的區別模型
- 各種資料庫的JDBC驅動下載及連線字串URL寫法資料庫JDBC字串
- 連線LilyPad之Linux平臺的驅動Linux
- linux驅動之LED驅動Linux
- 新字元驅動框架驅動LED字元框架
- 載入驅動三種execute
- CI3驅動器(drivers)建立與使用
- mysql驅動表、被驅動表、大表小表及join最佳化MySql
- 免安裝Oracle連線資料庫(odbc驅動)Oracle資料庫
- RMAN連線與oracle連線模式的關係Oracle模式
- 關於go和資料庫連線,客戶端以及驅動的疑問?Go資料庫客戶端
- win10顯示卡驅動怎麼更新 升級顯示卡驅動的兩種方法Win10
- 關於windows下安裝mysql的驅動,及安裝完驅動找不到ODBC驅動的解決辦法WindowsMySql
- 關於Oracle OCI驅動的使用Oracle
- 驅動精靈是幹嘛的 驅動精靈怎麼安裝驅動
- 事件驅動的微服務-事件驅動設計事件微服務
- MySQL JDBC驅動版本與資料庫版本的對應關係及注意事項MySqlJDBC資料庫
- 驅動Driver-platform平臺驅動Platform
- 阻止Win7系統自動安裝驅動程式的3種方法Win7
- 如何禁用win10自動更新驅動_win10關閉驅動自動更新的方法Win10
- VMware ESXi 8.0U3 macOS Unlocker & OEM BIOS 整合網路卡驅動和 NVMe 驅動 (整合驅動版)MaciOS