聊聊Oracle Optimizer相關的幾個引數(中)
我們繼續來介紹可以影響Oracle Optimizer工作的若干引數。
4、最佳化器引數2——cursor_sharing
Cursor_sharing是Oracle最佳化器的另一個重要引數,可能也是我們日常討論較多的一個引數。最開始的cursor_sharing提出,是建立在Oracle希望可以“一蹴而就”的解決hard parse,提高library cache中SQL執行計劃重用機率的“美好願望”下。在相當長的時間裡,很多DBA和開發人員都將這個引數視為“金手指”,認為只要開啟了這個引數,硬解析比例就會降低,效能瓶頸就會消除。
但是無論是從理論上,還是實際使用效果上,cursor_sharing都沒有實現當時的目標。
筆者在之前的Blog中,對cursor_sharing引數的含義、取值和效果乃至評價都有比較具體的闡述。有興趣的讀者可以參見下面列表系列:
《淺談cursor_sharing取值對SQL共享的影響》
http://space.itpub.net/17203031/viewspace-705196
http://space.itpub.net/17203031/viewspace-705289
SQL> show parameter cursor_shar
NAME TYPE VALUE
------------------------------------ ----------- ----------
cursor_sharing string EXACT
簡單的說,cursor_sharing引數對使用繫結變數的SQL語句是沒有效果和影響的。如果該引數設定為非EXACT,那些沒有使用繫結變數的SQL語句的where後面取值都會被預設的替換,並且進行一定程度的執行計劃共享。
但是,無論是cursor_sharing取值為familiar還是force,都存在其在遊標共享問題的不合理性。特別是其對所有SQL執行計劃處理的“一刀切”策略,是很有問題的。
在使用過程中,cursor_sharing也有各種問題,所以很快的大家就放棄了這種引數最佳化的思路。轉回到書寫繫結變數和避免bind peeking等方案上來。
進入11g之後,Adaptive Cursor Sharing技術的提出,意味著Oracle重新思考解決繫結變數的bind peeking問題。Cursor_sharing有傳言在下一個版本中一些取值會去除。
筆者認為:cursor_sharing是一種不成熟的嘗試。在一些特定場合下,可能存在使用的價值。但是作為資料架構師和開發人員,還是老老實實的寫繫結變數穩妥。運維DBA在面對沒有繫結變數的系統時候,也要慎用該引數。
5、最佳化引數3——db_file_multiblock_read_count
這個引數的作用,同Oracle進行物理IO的方式有關。Oracle進行的IO分為Logical IO和Physical IO兩種。不嚴格的說:進行物理IO的次數比例越高,系統效能瓶頸問題出現的多。
但是進行IO也是有不同之處的。進行一次IO的資料塊讀取量不同,可能會影響到Optimizer特別是CBO的成本計算。
在Oracle進行FTS(Full Table Scan)和Index Fast-Full Scan的時候,進行讀取的資料塊都是連續方式訪問的。因為作為資料段Data Segment和索引段Index Segment,都是由一系列內部連續資料塊組成的分割槽extent序列構成的。在進行這樣的操作時,獲取的資料塊大都是相鄰的。
如果我們進行一次物理IO時候,能夠多獲取到一些資料塊,那麼進行物理IO的絕對次數就會變少。這樣相應的成本就會降低。
SQL> show parameter db_file_mu
NAME TYPE VALUE
------------------------------------ ----------- -----------------------
db_file_multiblock_read_count integer 16
SQL> select value, display_value from v$parameter where name='db_file_multiblock_read_count';
VALUE DISPLAY_VA
---------- ----------
16 16
預設情況下,筆者實驗環境上的該引數為16,表示一次進行讀取的時候最多讀取到16個資料塊。
我們首先回顧一下在預設情況下,進行FTS操作的成本計算。
SQL> explain plan for select * from t where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 43272 | 3887K| 158 (3)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T | 43272 | 3887K| 158 (3)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER"='SYS')
SQL> explain plan for select * from t where object_id between 10 and 50000;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Plan hash value: 1601196873
------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 44865 | 4030K| 159 (4)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T | 44865 | 4030K| 159 (4)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"<=50000 AND "OBJECT_ID">=10)
注意,兩個進行FTS的執行計劃,Oracle最佳化器“估算出”的成本值為158和159。如果我們調整db_file_multiblock_read_count引數,觀察一下兩個SQL的執行計劃變化。
SQL> alter session set db_file_multiblock_read_count=300;
Session altered
SQL> select value, display_value from v$parameter where name='db_file_multiblock_read_count';
VALUE DISPLAY_VA
---------- ----------
128 128
我們嘗試將這個引數設定為300,但是最後還是調整為最大值128。這個引數雖然可以設定,但是最後還要受到伺服器體系結構和物理配置的影響。
此時兩個SQL的執行計劃如下。
SQL> explain plan for select * from t where wner='SYS';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 43300 | 3890K| 126 (4)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T | 43300 | 3890K| 126 (4)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OWNER"='SYS')
SQL> explain plan for select * from t where object_id between 10 and 50000;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 44849 | 4029K| 127 (4)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T | 44849 | 4029K| 127 (4)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("OBJECT_ID"<=50000 AND "OBJECT_ID">=10)
13 rows selected
當我們調整該引數之後,進行FTS操作計算出的成本變小。說明在計算執行計劃的過程中,如果db_file_multiblock_read_count引數設定變大,成本公式中成本值就會變小。
可以看出,該引數設定的較大,可以讓FTS操作成本估算的結果變小。進而,最終的生成執行計劃更傾向於FTS操作。
6、最佳化引數4——optimizer_mode
optimizer_mode也是Oracle早期使用的一個引數,主要是針對SQL執行計劃生成的目標導向。預設情況下,該引數取值為all_rows,表明執行計劃的生成是以最小成本消耗和吞吐量為標準。在all_rows的取值情況下,我們通常是對所有的結果集合進行一次性的處理操作。
與all_rows相對應的optimizer_mode引數是first_rows系列取值。該取值要求最佳化器以快速響應fast response作為執行計劃的生成依據。執行SQL的時候,Oracle會爭取將結果集合先返回給前端。
在實際使用中,單表操作情況下不同的optimizer_mode取值在執行計劃上沒有什麼差異。
我們首先準備實驗資料環境。
SQL> create table t_obj as select * from dba_objects;
Table created
SQL> create table t_tables as select * from dba_tables;
Table created
SQL> create index idx_t_obj_cmp on t_obj(owner,object_name);
Index created
SQL> create index idx_t_tables_cmp on t_tables(owner,table_name);
Index created
SQL> exec dbms_stats.gather_table_stats(user,'T_OBJ',cascade => true);
PL/SQL procedure successfully completed
SQL> exec dbms_stats.gather_table_stats(user,'T_TABLES',cascade => true);
PL/SQL procedure successfully completed
當進行單表操作的時候,first_rows與all_rows取值差異不是很大。
--設定optimizer_mode引數為all_rows
SQL> alter session set optimizer_mode='all_rows';
Session altered
SQL> select value from v$parameter where name='optimizer_mode';
VALUE
----------------------------------------------------
ALL_ROWS
SQL> explain plan for select * from t_obj;
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 | | 50387 | 4576K| 157 (3)| 00:00:02 |
| 1 | TABLE ACCESS FULL| T_OBJ | 50387 | 4576K| 157 (3)| 00:00:02 |
---------------------------------------------------------------------------
8 rows selected
--設定引數取值為optimizer_mode為first_rows
SQL> alter session set optimizer_mode='first_rows';
Session altered
SQL> select value from v$parameter where name='optimizer_mode';
VALUE
---------------------------------------------------------------
FIRST_ROWS
SQL> explain plan for select * from t_obj;
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 | | 50387 | 4576K| 157 (3)| 00:00:02 |
| 1 | TABLE ACCESS FULL| T_OBJ | 50387 | 4576K| 157 (3)| 00:00:02 |
---------------------------------------------------------------------------
8 rows selected
單表操作下,執行計劃是沒有什麼差異的。但是,在進行表連線操作的情況下,執行計劃有很大差異。
當引數為all_rows的時候,一般連線Oracle都儘量使用hash join連線方式,不使用index連線鍵。
SQL> alter session set optimizer_mode='all_rows';
Session altered
SQL> explain plan for select * from t_tables a, t_obj b where a.owner=b.owner and a.table_name=b.object_name;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 2309375240
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1606 | 467K| 171 (4)| 00:00:03 |
|* 1 | HASH JOIN | | 1606 | 467K| 171 (4)| 00:00:03 |
| 2 | TABLE ACCESS FULL| T_TABLES | 1606 | 321K| 12 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T_OBJ | 50387 | 4576K| 157 (3)| 00:00:02 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."OWNER"="B"."OWNER" AND
"A"."TABLE_NAME"="B"."OBJECT_NAME")
16 rows selected
雖然在連線鍵上有索引,Oracle使用hash join連線方式。Hash Join方式往往會忽視索引路徑。
如果我們將引數設定為first_rows,也就是儘量將先獲取的結果返回。Oracle會更加傾向與巢狀迴圈Nested Loop和索引連線Index Join。
SQL> alter session set optimizer_mode='first_rows';
Session altered
SQL> select value from v$parameter where name='optimizer_mode';
VALUE
------------------------------------------
FIRST_ROWS
SQL> explain plan for select * from t_tables a, t_obj b where a.owner=b.owner and a.table_name=b.object_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"."TABLE_NAME"="B"."OBJECT_NAME")
16 rows selected
根據原始的設計,all_rows取值適合於批作業、計算、選擇等常規業務場景。而first_rows主要適合在Web/Windows頁面分頁顯示場景。
在我們使用SQL的時候,預設還是將這個引數設定為all_rows,這樣適應性更好,執行計劃獲取更好。如果一些個別需要要求first_rows,可以使用hint進行特殊設定。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-720870/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 聊聊Oracle Optimizer相關的幾個引數(下)Oracle
- Oracle undo保留時間的幾個相關引數Oracle
- Linux系統中與記憶體相關的幾個核心引數Linux記憶體
- 幾個和MySQL InnoDB相關的引數設定說明MySql
- 並行相關的幾個引數並行
- oracle相關的linux核心引數OracleLinux
- MySQL的幾個和innodb相關的主要引數設定總結MySql
- oracle 身份認證相關引數Oracle
- 幾項網路安全相關的no引數詳解
- oracle sga配置相關的os 核心引數Oracle
- Linux 核心引數 和 Oracle相關引數調整LinuxOracle
- Linux 核心引數及Oracle相關引數調整LinuxOracle
- Oracle幾個初始化引數Oracle
- Oracle 11g中的_optimizer_null_aware_antijoin隱含引數OracleNull
- 【Oracle】-【sqlplus相關】-serveroutput引數OracleSQLServer
- oracle 安裝相關引數設定Oracle
- Oracle的AMM和ASMM以及相關引數探究OracleASM
- Oracle查詢優化器的相關引數Oracle優化
- Oracle優化相關的一些引數Oracle優化
- (轉)Linux 核心引數及Oracle相關引數調整LinuxOracle
- Optimizer_mode引數
- 引數OPTIMIZER_MODE
- Oracle 優化引數 optimizer_mode 介紹Oracle優化
- 伺服器中的幾個重要引數伺服器
- 10g中的optimizer_mode引數的取值
- Oracle安裝相關Linux引數(轉)OracleLinux
- 【轉】Oracle安裝相關Linux引數OracleLinux
- Spark的相關引數配置Spark
- linux 跟oracle相關的系統核心引數?LinuxOracle
- Oracle控制優化器偏好--optimizer_mode引數Oracle優化
- Oracle 最佳化引數 optimizer_mode 介紹Oracle
- oracle11g中的幾個記憶體初始化引數Oracle記憶體
- MySQL中Redo Log相關的重要引數總結MySql
- MySQL中的統計資訊相關引數介紹MySql
- 聊聊Oracle表空間Offline的三種引數(中)Oracle
- Oracle direct path read相關隱含引數Oracle
- Shell 中 $ 關於指令碼引數的幾種用法指令碼
- MySQL效能相關引數MySql