三、表關聯順序的HINT
1、leading hint
在多表關聯中,這個hint指定由哪個表作爲驅動表,告訴優化器先訪問哪個表的數據。
SQL> create table t1 as select 1 id,object_name name from dba_objects;
Table created.
SQL> create index ind_t1 on t1(id,name);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true,estimate_percent=>100);
PL/SQL procedure successfully completed.
SQL> drop table t;
Table dropped.
SQL> create table t as select object_id id,object_name name from dba_objects;
Table created.
SQL> create index ind_t on t(id,name);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'t',cascade=>true,estimate_percent=>100);
PL/SQL procedure successfully completed.
要求先訪問T1,再訪問T
SQL> select /*+ leading(t1,t) */ t.* from t,t1 where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1444793974
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 31 | 116 (5)| 00:00:02 |
|* 1 | HASH JOIN | | 1 | 31 | 116 (5)| 00:00:02 |
| 2 | TABLE ACCESS FULL| T1 | 50604 | 148K| 55 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T | 50604 | 1383K| 59 (4)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."ID"="T"."ID")
要求先訪問T,再訪問T1
SQL> select /*+ leading(t,t1) */ t.* from t,t1 where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 2914261090
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 31 | | 249 (3)| 00:00:03 |
|* 1 | HASH JOIN | | 1 | 31 | 1984K| 249 (3)| 00:00:03 |
| 2 | TABLE ACCESS FULL| T | 50604 | 1383K| | 59 (4)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T1 | 50604 | 148K| | 55 (2)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."ID"="T"."ID")
爲什麼先訪問T1的代價低?
因爲T1表的ID列重複率比較高,意味着生成的哈西簇會比較少,
而hash join這個過程的代價主要是耗在生成hash簇的過程,
意味着只要哈西簇少代價就會降低;
T表的ID列重複率是很低的,生成的hash簇會比較多,此時代價自然比先訪問T1要高。
結論——hash join的性能主要取決於哈西簇的生成。
2、orderd hint
告訴優化器按照from後面的順序來選擇驅動表,oracle建議用leading,比較靈活。
SQL> select /*+ ordered */ t.* from t,t1 where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 2914261090
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 31 | | 249 (3)| 00:00:03 |
|* 1 | HASH JOIN | | 1 | 31 | 1984K| 249 (3)| 00:00:03 |
| 2 | TABLE ACCESS FULL| T | 50604 | 1383K| | 59 (4)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T1 | 50604 | 148K| | 55 (2)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."ID"="T"."ID")
SQL> select /*+ ordered */ t.* from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1444793974
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 31 | 116 (5)| 00:00:02 |
|* 1 | HASH JOIN | | 1 | 31 | 116 (5)| 00:00:02 |
| 2 | TABLE ACCESS FULL| T1 | 50604 | 148K| 55 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T | 50604 | 1383K| 59 (4)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("T1"."ID"="T"."ID")
四、表關聯方式的hint
/*+ use_nl(t t1) */
/*+ use_hash(t t1) */
/*+ use_merge(t t1) */
當使用很多hint的時候
SQL> select /*+ leading(t,t1) index(t1 ind_t1) index(t ind_t) use_nl(t t1) */ t.* from t,t1 where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 2389647923
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 31 | 50949 (1)| 00:10:12 |
| 1 | NESTED LOOPS | | 1 | 31 | 50949 (1)| 00:10:12 |
| 2 | INDEX FULL SCAN | IND_T | 50604 | 1383K| 286 (1)| 00:00:04 |
|* 3 | INDEX RANGE SCAN| IND_T1 | 1 | 3 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T1"."ID"="T"."ID")
研究一下三種連接方式的sql trace
SQL> drop table t1;
Table dropped.
SQL> create table t1 as select * from t;
Table created.
SQL> create index ind_t1 on t1(id,name);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true,estimate_percent=>100);
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'t',cascade=>true,estimate_percent=>100);
PL/SQL procedure successfully completed.
SQL> set autotrace off
SQL> alter session set sql_trace=true;
Session altered.
SQL> select /*+ use_nl(t1 t) */ count(1) from t1,t where t1.id=t.id;
COUNT(1)
----------
50604
SQL> select /*+ use_hash(t1 t) */ count(1) from t1,t where t1.id=t.id;
COUNT(1)
----------
50604
SQL> select /*+ use_merge(t1 t) */ count(1) from t1,t where t1.id=t.id;
COUNT(1)
----------
50604
SQL> alter session set sql_trace=false;
Session altered.
[oracle@oracle253 udump]$ tkprof law_ora_7171.trc law_ora_7171_text.txt
TKPROF: Release 10.2.0.4.0 - Production on Tue Aug 27 16:34:57 2013
Copyright (c) 1982, 2007, Oracle. All rights reserved.
*******************************************************************************
count = number of times OCI procedure was executed
cpu = cpu time in seconds executing
elapsed = elapsed time in seconds executing
disk = number of physical reads of buffers from disk
query = number of buffers gotten for consistent read
current = number of buffers gotten in current mode (usually for update)
rows = number of rows processed by the fetch or execute call
********************************************************************************
select /*+ use_nl(t1 t) */ count(1)
from
t1,t where t1.id=t.id
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.22 0.23 0 51131 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.22 0.23 0 51131 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 57
Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE (cr=51131 pr=0 pw=0 time=234288 us)
50604 NESTED LOOPS (cr=51131 pr=0 pw=0 time=253094 us)
50604 TABLE ACCESS FULL T1 (cr=243 pr=0 pw=0 time=48 us)
50604 INDEX RANGE SCAN IND_T (cr=50888 pr=0 pw=0 time=174963 us)(object id 52948)
********************************************************************************
select /*+ use_hash(t1 t) */ count(1)
from
t1,t where t1.id=t.id
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.04 0.05 0 486 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.04 0.05 0 486 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 57
Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE (cr=486 pr=0 pw=0 time=55377 us)
50604 HASH JOIN (cr=486 pr=0 pw=0 time=131253 us)
50604 TABLE ACCESS FULL T1 (cr=243 pr=0 pw=0 time=47 us)
50604 TABLE ACCESS FULL T (cr=243 pr=0 pw=0 time=33 us)
********************************************************************************
select /*+ use_merge(t1 t) */ count(1)
from
t1,t where t1.id=t.id
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.16 0.17 0 486 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.16 0.17 0 486 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 57
Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE (cr=486 pr=0 pw=0 time=175407 us)
50604 MERGE JOIN (cr=486 pr=0 pw=0 time=195280 us)
50604 SORT JOIN (cr=243 pr=0 pw=0 time=29292 us)
50604 TABLE ACCESS FULL T1 (cr=243 pr=0 pw=0 time=54 us)
50604 SORT JOIN (cr=243 pr=0 pw=0 time=101547 us)
50604 TABLE ACCESS FULL T (cr=243 pr=0 pw=0 time=48 us)
********************************************************************************
OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 4 0.00 0.00 0 0 0 0
Execute 4 0.00 0.00 0 0 0 0
Fetch 6 0.43 0.46 0 52103 0 3
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 14 0.43 0.47 0 52103 0 3
Misses in library cache during parse: 3
OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 0 0.00 0.00 0 0 0 0
Execute 0 0.00 0.00 0 0 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 0 0.00 0.00 0 0 0 0
Misses in library cache during parse: 0
4 user SQL statements in session.
0 internal SQL statements in session.
4 SQL statements in session.
********************************************************************************
比較一致性讀:
NL方式——51131
HASH方式——486
MERGE方式——486
一致性讀一樣但是執行計劃不一樣
SQL> set autotrace trace exp
SQL> select /*+ use_hash(t1 t) */ count(1) from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 949044725
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 119 (5)| 00:00:02 |
| 1 | SORT AGGREGATE | | 1 | 10 | | |
|* 2 | HASH JOIN | | 50604 | 494K| 119 (5)| 00:00:02 |
| 3 | TABLE ACCESS FULL| T1 | 50604 | 247K| 58 (2)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T | 50604 | 247K| 58 (2)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."ID"="T"."ID")
SQL> select /*+ use_merge(t1 t) */ count(1) from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 712353386
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | | 442 (4)| 00:00:06 |
| 1 | SORT AGGREGATE | | 1 | 10 | | | |
| 2 | MERGE JOIN | | 50604 | 494K| | 442 (4)| 00:00:06 |
| 3 | SORT JOIN | | 50604 | 247K| 1208K| 221 (4)| 00:00:03 |
| 4 | TABLE ACCESS FULL| T1 | 50604 | 247K| | 58 (2)| 00:00:01 |
|* 5 | SORT JOIN | | 50604 | 247K| 1208K| 221 (4)| 00:00:03 |
| 6 | TABLE ACCESS FULL| T | 50604 | 247K| | 58 (2)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access("T1"."ID"="T"."ID")
filter("T1"."ID"="T"."ID")
選擇cost較小的hash join方式。
結論:大表間的訪問,HASH方式性能更高,NL最差,當驅動表是小表的時候,NL的性能纔會體現出來。
改造表,將T表變爲小表
SQL> truncate table t;
Table truncated.
SQL> insert into t select object_id,object_name from dba_objects where rownum<10;
9 rows created.
SQL> commit;
Commit complete.
SQL> exec dbms_stats.gather_table_stats(user,'t',cascade=>true,estimate_percent=>100);
PL/SQL procedure successfully completed.
SQL> select count(1) from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 2183851067
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 10 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
| 2 | NESTED LOOPS | | 9 | 72 | 10 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | IND_T | 9 | 27 | 1 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN| IND_T1 | 1 | 5 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."ID"="T"."ID")
強制hash join
SQL> select /*+ use_hash(t1 t) */ count(1) from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 596805104
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 61 (5)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | HASH JOIN | | 9 | 72 | 61 (5)| 00:00:01 |
| 3 | INDEX FULL SCAN | IND_T | 9 | 27 | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T1 | 50604 | 247K| 58 (2)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."ID"="T"."ID")
禁用連接方式
A 禁用使用NL,會在剩下的兩種連接方式中選擇次優的。
SQL> select /*+ no_use_nl(t1 t) */ count(1) from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 596805104
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 61 (5)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | HASH JOIN | | 9 | 72 | 61 (5)| 00:00:01 |
| 3 | INDEX FULL SCAN | IND_T | 9 | 27 | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T1 | 50604 | 247K| 58 (2)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T1"."ID"="T"."ID")
B 禁止使用hash join
/*+ no_use_hash(t1 t) */
C 禁止使用merge join
/*+ no_use_merge(t1 t) */
五、與並行相關的hint
SQL> select /*+ parallel(t1 4) parallel(t 3) */ count(1) from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 3903087583
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 5 (0)| 00:00:01 | | | |
| 1 | SORT AGGREGATE | | 1 | 8 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | 8 | | | Q1,00 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 8 | | | Q1,00 | PCWP | |
| 5 | NESTED LOOPS | | 9 | 72 | 5 (0)| 00:00:01 | Q1,00 | PCWP | |
| 6 | PX BLOCK ITERATOR | | | | | | Q1,00 | PCWC | |
| 7 | TABLE ACCESS FULL| T | 9 | 27 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
|* 8 | INDEX RANGE SCAN | IND_T1 | 1 | 5 | 1 (0)| 00:00:01 | Q1,00 | PCWP | |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
8 - access("T1"."ID"="T"."ID")
PX出現表示用了並行的方式。
SQL> conn /as sysdba
Connected.
SQL> select table_name,degree from dba_tables where owner='SCOTT' and table_name like 'T%';
TABLE_NAME DEGREE
------------------------------------------------------------------------------
T 1
T1 1
默認的並行度
SQL> conn scott/scott
Connected.
SQL> alter table t parallel 3;
Table altered.
SQL> alter table t1 parallel 4;
Table altered.
SQL> select table_name,degree from dba_tables where owner='SCOTT' and table_name like 'T%';
TABLE_NAME DEGREE
------------------------------------------------------------------------------
T 3
T1 4
SQL> select count(1) from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 3903087583
-----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 5 (0)| 00:00:01 | | | |
| 1 | SORT AGGREGATE | | 1 | 8 | | | | | |
| 2 | PX COORDINATOR | | | | | | | | |
| 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | 8 | | | Q1,00 | P->S | QC (RAND) |
| 4 | SORT AGGREGATE | | 1 | 8 | | | Q1,00 | PCWP | |
| 5 | NESTED LOOPS | | 9 | 72 | 5 (0)| 00:00:01 | Q1,00 | PCWP | |
| 6 | PX BLOCK ITERATOR | | | | | | Q1,00 | PCWC | |
| 7 | TABLE ACCESS FULL| T | 9 | 27 | 2 (0)| 00:00:01 | Q1,00 | PCWP | |
|* 8 | INDEX RANGE SCAN | IND_T1 | 1 | 5 | 1 (0)| 00:00:01 | Q1,00 | PCWP | |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
8 - access("T1"."ID"="T"."ID")
禁止並行
SQL> select /*+ no_parallel(t1) no_parallel(t) */ count(1) from t1,t where t1.id=t.id;
Execution Plan
----------------------------------------------------------
Plan hash value: 2183851067
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 10 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
| 2 | NESTED LOOPS | | 9 | 72 | 10 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | IND_T | 9 | 27 | 1 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN| IND_T1 | 1 | 5 | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."ID"="T"."ID")
六、動態採樣
/*+ dynamic_sampling(t 4) */
七、其他的
cache hint
在全表掃描的操作中,如果使用這個提示,oracle會將掃到的數據塊放在LRU鏈表最被使用端,
這樣的話,數據塊可以長時間駐留內存。
場合:如果一個經常被訪問的小表,這個設置可以提高查詢的性能。
SQL> select /*+ full(emp) cache(emp) */ * from emp;
Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 14 | 1218 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| EMP | 14 | 1218 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement
與KEEP池的區別,這個hint是好用db buffer的默認池大小,
keep池是另外的區域,長時間駐留在內存中KEEP池區域中。
區別在於在內存中的位置不一樣。
相同點——效果是一樣的,爲了放到內存,提高緩存的命中率。