Sql最佳化(二) 關聯(join)
一、 JOIN的分類
(一) Nested loop join
1. 適用條件
1)關聯少量資料(rows),返回集小
2)關聯條件能高效訪問第二張表(inner table)。高效訪問的關聯條件如'=',反之非高效的關聯條件如'!=','>'等;inner table(即非驅動表)上要有索引。
因此比較適合OLTP系統,因為OLTP系統中一般返回資料量小,而且表上面索引較多。[@more@]
2. 實現步驟
1) 最佳化器選擇驅動表(driving table),指定其為outer table
2) 指定另一張表為inner table(非驅動表)
3) 根據outer table的每行記錄的關聯欄位,來訪問inner table。如下所示:
NESTED LOOPS
outer_loop
inner_loop
由於Nested loop從outer table向inner table查詢,關聯的次序就比較重要了。
3. nested loop join的例子
SELECT e.first_name, e.last_name, e.salary, d.department_name
FROM hr.employees e, hr.departments d
WHERE d.department_name IN ('Marketing', 'Sales')
AND e.department_id = d.department_id;
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 19 | 722 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 10 | 220 | 1 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 19 | 722 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | DEPARTMENTS | 2 | 32 | 2 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 10 | | 0 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------
(二) Hash join
1. 適用條件
1) 僅用於等值關聯equijoin(如=);
2) 滿足下列任一條件:
大表關聯
或者小表的大部分記錄參與關聯
2. 實現機制
1) 最佳化器選擇較小的表,基於join key構建hash table。(驅動表)
2) 掃描另外一張較大的表,並在hash table中搜尋關聯行
如果記憶體足夠,小表全部在記憶體中,這種情況是最優的,成本可估算為兩張表各一次全表讀。
如果記憶體不夠,則小表的一部分可以放在temporary tablespace中(Temp表空間應足夠大),以儘可能提高io速度。
3. 例子
SELECT o.customer_id, l.unit_price * l.quantity
FROM orders o ,order_items l
WHERE l.order_id = o.order_id;
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 665 | 13300 | 8 (25)|
|* 1 | HASH JOIN | | 665 | 13300 | 8 (25)|
| 2 | TABLE ACCESS FULL | ORDERS | 105 | 840 | 4 (25)|
| 3 | TABLE ACCESS FULL | ORDER_ITEMS | 665 | 7980 | 4 (25)|
--------------------------------------------------------------------------
(三) Sort merge join
1. 適用情況
通常情況下hash join效能更好,但如果關聯的資料已經排序或不需排序,則sort merge join效能會更好
非等值關聯(nonequi join,如<,> )時很有用,因為sort merge join在返回集很大時比nested loop效能好,而hash join又只能在equijoin中使用。
2. 實現機制
1) Sort操作:關聯資料按照關聯欄位進行排序。如果資料本來就是排序的,就不需此操作
2) Merge操作:經過排序的資料進行merge操作。
需要說明的是,sort merge join沒有driving table的概念
(四) 笛卡爾連線
無關聯條件,應儘可能避免。
(五) Outer join
是simple join的擴充套件,
SELECT cust_last_name, sum(nvl2(o.customer_id,0,1)) "Count"
FROM customers c, orders o
WHERE c.credit_limit > 1000
AND c.customer_id = o.customer_id(+)
C表稱為preserved table,o表稱為optional table
Outer join分為:
Left outer join
Right outer join
Full outer join
和普通join相比,outer join也可以是nested loop、hash join、sort merge等。但有一些不同之處:
1. Nested loop outer join中,以preserved table作為驅動表,而不是像普通join基於cost來選擇驅動表
2. Full outer join(equijoin)在11g中,自動使用基於hash join的演算法。執行計劃中出現HASH JOIN FULL OUTER。
可以用hint:NATIVE_FULL_OUTER_JOIN/NO_NATIVE_FULL_OUTER_JOIN來指定使用或不使用這一演算法。如果不使用,則full outer jion的執行計劃是left outer join和right outer jion的union。
二、 Join次序
基本原則是:記錄少的先關聯,這樣參與後續關聯的記錄數就會少。具體來說:
1)選擇能排除掉最多記錄的表作為driving table
2)剩餘的表中,選選擇有最好的filter的表(排除最多記錄)作為首先參與關聯的表
3)以此類推
看這個例子:
SELECT info
FROM taba a, tabb b, tabc c
WHERE a.acol BETWEEN 100 AND 200
AND b.bcol BETWEEN 10000 AND 20000
AND c.ccol BETWEEN 10000 AND 20000
AND a.key1 = b.key1
AND a.key2 = c.key2;假設a表經過filter後記錄最少,b次之,c記錄最多。那麼可以用a作為driving table,先與b關聯,最後與c關聯
三. 使用hint選擇關聯方式和次序
(一)使用hint指定關聯方式
Oracle最佳化器自動選擇join的方式,但有時不是最優的,開發人員可使用hint來選擇join方式,比較執行效率。相關的hint有:
USE_NL,USE_HASH,USE_MERGE
Exists子句中,HASH_SJ,MERGE_SJ,NL_SJ
Not in子句中,HASH_AJ,MERGE_AJ,NL_AJ
(二) 使用hint指定關聯次序
如果oracle最佳化器選擇的關聯次序不是你所希望的,可以用hint(leading和ordered)來指定。Ordered表示按照sql語句中表出現的先後次序,leading則可任意指定,更為通用。
Leading指定了driving table的選定次序。(在nested loop中,driving table就是outer table,在hash join中,是hash table。)
SELECT /*+ leading (a b c) */info
WHERE a.acol BETWEEN 100 AND 200
AND b.bcol BETWEEN 10000 AND 20000
AND c.ccol BETWEEN 10000 AND 20000
AND a.key1 = b.key1
AND a.key2 = c.key2;
(三) Undocumented hint引數:swap_join_inputs
注意,上面例子中,a作為驅動表和b關聯,關聯結果作為驅動表,再和c關聯。有時需要改變次序,如下面例子
SELECT /*+ leading (a b c)*/ info
WHERE a.key1 = b.key1
AND b.key2 = c.key2;
假如a 1000條,b 10萬條,c 1萬條。由於a和c表沒有關聯欄位,因此a和b先關聯,再和c關聯。但a關聯b產生2萬條記錄,和c關聯時,希望以c為驅動表,能否實現呢?
在hash_join中可以用oracle的隱含hint引數swap_join_inputs實現:
SELECT /*+ leading (a b c) swap_join_inputs(c) */ info
WHERE a.key1 = b.key1
AND b.key2 = c.key2;
詳見metalink:How to switch the driving table in a hash join [ID 171940.1]
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25462274/viewspace-2124907/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SQL最佳化 之 -- joinSQL
- 【SQL】13 SQL 別名、SQL 連線(JOIN)、SQL INNER JOIN 關鍵字、SQL LEFT JOIN 關鍵字、SQL RIGHT JOIN 關鍵字、SQL FULL OUTER JSQL
- MySQL表關聯join方式MySql
- sql語句左連結left join--3張表關聯SQL
- straight_join最佳化sql語句AISQL
- SQL INNER JOIN 關鍵字 用法SQL
- SQL joinSQL
- 三表關聯查詢-多次LEFT JOIN...ON
- sql中的join、left join、right joinSQL
- 關於關聯查詢sql的一次最佳化過程及其他SQL
- 有關Bitmap Join Indexes的精彩帖二Index
- Oracle SQL JOINOracleSQL
- SQL -- JOIN子句SQL
- sql:left join和join區別SQL
- 微課sql最佳化(15)、表的連線方法(4)-關於Hash Join(雜湊連線)SQL
- MySQL INNER JOIN關聯多張表的寫法MySql
- 微課sql最佳化(16)、表的連線方法(5)-關於Merge Join(排序合連線)SQL排序
- SQL not exist out joinSQL
- SQL Server Left joinSQLServer
- sql之left join、right join、inner join的區別SQL
- Sqlserver update\delete用inner join關聯,會update\delete關鍵字後面的表關聯到的行SQLServerdelete
- sql left join 和 right join解釋SQL
- 微課sql最佳化(14)、表的連線方法(3)-關於Nested Loops Join(巢狀迴圈)SQLOOP巢狀
- ORACLE SQL效能最佳化系列 (二) (轉)OracleSQL
- SQL中聯表查詢操作(LEFT JOIN, RIGHT JOIN, INNER JOIN)SQL
- 【原】Oracle中Left Outer Join和外關聯(+)的區別Oracle
- SQL 不知道咋最佳化?吹一手 join 語句的最佳化準沒錯SQL
- sql的left join 、right join 、inner join之間的區別SQL
- Sql 之 join 001SQL
- sql語言中join操作SQL
- sql編寫與業務關聯SQL
- 【MySQL】 效能最佳化之 延遲關聯MySql
- SQL*Loader 筆記 (二) 效能最佳化SQL筆記
- SQL語句中不同的連線JOIN及SQL中join的各種用法SQL
- MySQL join語句怎麼最佳化?MySql
- sql語句中JOIN ON 的使用SQL
- sql join例項圖解SQL圖解
- SQL JOIN 簡單介紹SQL