聊聊Oracle Optimizer相關的幾個引數(下)
最後我們介紹幾個可能影響到Optimizer的系統引數。
7、最佳化引數5——optimizer_index_caching
引數optimizer_index_caching的含義在於一個估算值,就是告訴最佳化器當進行索引路徑檢索的時候,特別是nested loop連線時索引探知(index probe)的成本。該引數的取值範圍是0-100,描述使用索引的時候,索引在buffer cache中的比例。這個引數的選取會影響到nested loop和in-list迴圈的成本估算值。
預設情況下,Oracle這個引數取值為0。
SQL> show parameter optimizer_index_cach
NAME TYPE VALUE
------------------------------------ ----------- --------------------------
optimizer_index_caching integer 0
如果這個取值設定為100,就表示在使用索引路徑的時候,所檢索的索引塊在buffer cache中都已經快取住。注意,這個引數只是一個估計值,是我們進行控制成本公式使用的。真正在執行的時候,索引塊在buffer cache中的比例是不能預知的!!
顯而易見,在控制這個引數的前提下,Oracle在計算索引路徑執行計劃的時候,成本值就自然有所降低。進而,最後CBO選擇出的執行計劃就更加傾向於索引路徑和Nested Loop連線方式。
我們透過下面簡單的實驗去驗證。我們首先看看非連線條件下的索引路徑成本計算,選取上面引數實驗t_obj和t_tables作為實驗環境。
--補充索引構建
SQL> create index idx_t_obj_owner on t_obj(owner);
Index created
SQL> exec dbms_stats.gather_table_stats(user,'T_OBJ',cascade => true);
PL/SQL procedure successfully completed
分別在optimizer_index_caching兩個極端情況下進行試驗。
--在取值為0的時候進行試驗;
SQL> alter session set optimizer_index_caching=0;
Session altered
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------
Plan hash value: 2947685431
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 2
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 25 | 2325 | 2
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 25 | | 1
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
14 rows selected
--修改引數
SQL> alter session set optimizer_index_caching=100;
Session altered
SQL> select value from v$parameter where name='optimizer_index_caching';
VALUE
-------------------------------
100
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------
Plan hash value: 2947685431
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 2
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 25 | 2325 | 2
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 25 | | 1
-----------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
14 rows selected
雖然都是進行索引路徑,但是對最後成本值影響不大。究其原因,可能是筆者選擇的選擇率過小的原因。
下面實驗nested loop路徑成本情況。
SQL> alter session set optimizer_index_caching=0;
Session altered
SQL> explain plan for select /*+ use_nl(a, b)*/* from t_obj a, t_tables b where a.owner=b.owner and a.object_name=b.table_name;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 2368859676
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1606 | 467K| 3229 (1
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 1 | 93 | 2 (0
| 2 | NESTED LOOPS | | 1606 | 467K| 3229 (1
| 3 | TABLE ACCESS FULL | T_TABLES | 1606 | 321K| 12 (0
|* 4 | INDEX RANGE SCAN | IDX_T_OBJ_CMP | 1 | | 1 (0
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("A"."OWNER"="B"."OWNER" AND "A"."OBJECT_NAME"="B"."TABLE_NAME")
16 rows selected
當進行強制的nested loop路徑選擇之後,我們在index_caching引數為0的時候,成本為3229,主要消耗在進行nested loop連線路徑上。那麼,當我們修改為100時,執行計劃如何變化呢?
SQL> alter session set optimizer_index_caching=100;
Session altered
SQL> explain plan for select /*+ use_nl(a, b)*/* from t_obj a, t_tables b where a.owner=b.owner and a.object_name=b.table_name;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 709597304
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1606 | 467K| 789
| 1 | TABLE ACCESS BY INDEX ROWID| T_TABLES | 1 | 205 | 1
| 2 | NESTED LOOPS | | 1606 | 467K| 789
| 3 | TABLE ACCESS FULL | T_OBJ | 50387 | 4576K| 157
|* 4 | INDEX RANGE SCAN | IDX_T_TABLES_CMP | 1 | | 0
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("A"."OWNER"="B"."OWNER" AND "A"."OBJECT_NAME"="B"."TABLE_NAME")
16 rows selected
效果非常明顯,成本值只有789。說明該引數在成本路徑計算中的作用和分量。但是,再次強調:引數只是控制和影響CBO進行決策的手段,它們只能影響到最後執行計劃的決策選擇,真正的執行時間還要看實際的環境和資料情況而定。
8、最佳化引數6——optimizer_index_cost_adj
該引數也是用來調整索引路徑成本的。簡單的說,optimizer_index_cost_adj引數就是索引路徑偏好的“縮放燈”。引數取值範圍為0-10000,預設為100。
SQL> show parameter optimizer_index_cost
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
optimizer_index_cost_adj integer 100
當Oracle依據統計量(資料表、索引物件)計算出index access路徑成本之後,會根據這個引數進行一定比例的放大和縮小。例如,如果該引數設定為10,表示會對索引路徑執行計劃的成本進行10%的縮小。
應用該引數,我們可以控制索引路徑的偏好度,放大或者縮小CBO成本計算公式中索引路徑成本的計算值。進而控制實際選擇出的執行計劃。
下面我們根據實驗來體會效果,我們同樣適用兩個SQL語句在三個引數取值下的情況進行實驗。
首先,我們選擇預設的optimizer_index_cost_adj取值下的情況。
SQL> select value from v$parameter where name='optimizer_index_cost_adj';
VALUE
------------------------------
100
SQL> explain plan for select * from t_obj where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------
Plan hash value: 172510092
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 22351 | 2029K| 156 (2)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T_OBJ | 22351 | 2029K| 156 (2)| 00:00:02 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER"='SYS')
13 rows selected
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Plan hash value: 2947685431
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 2
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 25 | 2325 | 2
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 25 | | 1
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
14 rows selected
下面,我們縮小引數值到10,也就是縮小索引路徑成本到原來的10%。
SQL> alter session set optimizer_index_cost_adj=10;
Session altered
SQL> explain plan for select * from t_obj where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------
Plan hash value: 2947685431
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 22351 | 2029K| 65
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 22351 | 2029K| 65
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 22351 | | 5
------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SYS')
14 rows selected
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------
Plan hash value: 2947685431
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 1
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 25 | 2325 | 1
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 25 | | 1
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT')
14 rows selected
我們看到了實驗現象:對owner=’SYS’而言,當不進行索引路徑成本縮放的時候索引路徑的成本是要高於全表掃描FTS的,所以CBO選擇了FTS作為路徑計算。但是,當我們將引數設定為10,也就是進行10%比例的縮放時,索引路徑的成本就下降到了65,小於FTS的156成本值。結果CBO在這種情況下選擇了索引路徑。
當owner=’SCOTT’語句中,成本也有一定程度的降低。因為取值本身就很小了,所以減小效果不明顯。
下面我們將引數調節到另一個極端,引數放大到10000。
SQL> alter session set optimizer_index_cost_adj=10000;
Session altered
SQL> explain plan for select * from t_obj where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------
Plan hash value: 172510092
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 22351 | 2029K| 156 (2)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T_OBJ | 22351 | 2029K| 156 (2)| 00:00:02 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER"='SYS')
13 rows selected
--強制的索引路徑;
SQL> explain plan for select /*+ index(t_obj IDX_T_OBJ_OWNER)*/* from t_obj where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2947685431
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%C
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 22351 | 2029K| 64906
| 1 | TABLE ACCESS BY INDEX ROWID| T_OBJ | 22351 | 2029K| 64906
|* 2 | INDEX RANGE SCAN | IDX_T_OBJ_OWNER | 22351 | | 5283
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SYS')
14 rows selected
上面的實驗中,我們將索引路徑的成本放大了100倍。原有的owner=’SYS’語句重新選擇了FTS路徑。如果我們強迫它去走索引路徑,結果成本計算出的64906,恰恰是之前650成本值的近100倍。
那麼,owner=’SCOTT’結果情況如何呢?
SQL> explain plan for select * from t_obj where wner='SCOTT';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------
Plan hash value: 172510092
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25 | 2325 | 156 (2)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T_OBJ | 25 | 2325 | 156 (2)| 00:00:02 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER"='SCOTT')
13 rows selected
owner=’SCOTT’選擇率極低,但是在放大100倍的效應下,CBO也放棄了索引路徑,選擇了FTS作為最終執行計劃。
9、結論
Oracle Optimizer本質上,就是一系列計算公式比較。我們提供資料物件的統計量,外加適當的引數作為引導,最後可以幫助CBO去生成更好的執行計劃。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-720953/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle undo保留時間的幾個相關引數Oracle
- Oracle安裝相關Linux引數(轉)OracleLinux
- 聊聊Oracle表空間Offline的三種引數(下)Oracle
- Oracle direct path read相關隱含引數Oracle
- 資料庫管理-第123期 Oracle相關兩個引數(202301205)資料庫Oracle
- 【PARANETERS】Oracle異常恢復相關的隱含引數Oracle
- pga相關引數
- Spark的相關引數配置Spark
- ORACLE並行相關的引數Oracle並行
- 【測試】Android Studio 相關下載及引數Android
- MySQL效能相關引數MySql
- PostgreSQL AutoVacuum 相關引數SQL
- 聊聊Oracle表空間Offline的三種引數(上)Oracle
- 聊聊Oracle表空間Offline的三種引數(中)Oracle
- MySQL 連線相關引數MySql
- 聊聊eureka的preferSameZoneEureka引數
- Oracle11g 自動化建庫及調整相關引數Oracle
- 4.2.10.1 Oracle Restart 相關變數配置OracleREST變數
- Java Thread 類相關的幾個核心方法Javathread
- Oracle 21c新特性預覽與日常管理相關的幾個新特性Oracle
- mysql relay log相關引數說明MySql
- redis持久化相關引數解釋Redis持久化
- [20191204]hugepage相關引數含義.txt
- openGauss執行緒池相關引數執行緒
- [20220913]hugepage相關引數含義.txt
- 聊聊jdk httpclient的retry引數JDKHTTPclient
- 伺服器中的幾個重要引數伺服器
- 聊聊Oracle外來鍵約束(Foreign Key)的幾個操作選項Oracle
- MySQL索引統計資訊更新相關的引數MySql索引
- MySQL中Redo Log相關的重要引數總結MySql
- Oracle相關命令Oracle
- PostgreSQL並行查詢相關配置引數SQL並行
- Shell 中 $ 關於指令碼引數的幾種用法指令碼
- 聊聊FluxFlatMap的concurrency及prefetch引數UX
- 動態許可權相關的幾個庫分析
- mysql鎖分析相關的幾個系統檢視MySql
- 執行緒中的幾個退出相關函式執行緒函式
- UIView中與AutoLayout相關的幾個方法對比UIView
- Linux命令列中幾個使用history相關的技巧Linux命令列