日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Oracle优化04-Optimizer优化器

發布時間:2025/3/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Oracle优化04-Optimizer优化器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  • 思維導圖
  • Optimizer概述
  • RBORule Based Optimizer
    • RBO概述
    • 案例說明
  • CBOCost Based Optimizer
    • CBO概述
    • 案例說明
    • 全表掃描
    • 索引掃描

思維導圖


Optimizer概述

Oracle數據庫中的優化器是SQL分析和執行的優化工具,它負責制定SQL的執行計劃,也就是它負責保證SQL執行效率最高.

比如優化器決定Oracle是以什么樣的方式方式訪問數據,是全表掃描(Full Table Scan) 、索引范圍掃描(Index Range Scan)還是全索引快速掃描(INDEX Fast Full Scan, INDEX_FFS).

對于多表關聯查詢,它負責確定表之間以一種什么樣的方式來關聯,比如Hash Join 還是 NESTED LOOPS或者是MERGE JOIN。

這些因素直接決定著SQL的執行效率,所以優化器是SQL執行的核心,它做出的執行計劃的好壞,直接決定了SQL的執行效率。

Oracle的優化器有兩種

  • RBO 基于規則的優化器
  • CBO 基于代價的優化器

從ORACLE10G開始,RBO已經被棄用(但是我們依然可以通過HINT的方式使用它)。


RBO(Rule Based Optimizer)

RBO概述

在8i之前,ORACLE使用RBO(Rule Based Optimizer 基于規則的優化器)優化器。

它的執行機制非常簡單,就是在優化器里面嵌入各種若干規則,執行的SQL符合那種規則,則按照對應的規則制定出相應的執行計劃。

比如表上有索引,如果謂詞上有索引的列存在,則ORACLE會選擇索引,否則全表掃描。

又比如兩個表關聯的時候,按照表在SQL中的位置來決定哪個是驅動表,哪個是被驅動表。

RBO選擇執行計劃的優先級列表如下:

其中,排名越靠前,Oracle認為效率越高。例如:按索引訪問的效率肯定高于全表掃描,多字段復合索引的效率高于單字段索引,等等。可見,RBO策略其實很簡單。而且在SQL語句存在多個索引時,由于無法判別各個索引的可選性,RBO的分析過程與語句的語法相關,如where條件順序,或者隨機選取。

通俗地講,RBO就是不關心被訪問對象的實際數據分布情況、索引效率等,僅憑想象去決定應該如何去訪問數據庫。可見,RBO是一種非常粗放型的優化器。


案例說明

思考:表中有索引,數據就必須選擇索引嗎?

首先創建一個數據分部非常不均勻的表

Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 Connected as xxx@xgj##建表 SQL> create table t as select 1 id ,object_name from dba_objects ;Table created ##更新一條數據 SQL> update t set id=99 where rownum=1;1 row updatedSQL> commit;Commit complete ##創建索引 SQL> create index idx_t on t(id);Index createdSQL> select id,count(1) from t group by id ;ID COUNT(1) ---------- ----------1 3525199 1

現在表中的數據 id =1 的 35251條記錄, id =99 的 1條記錄。

如果發出兩條這樣的SQL

SQL> select * from t where t.id=1; SQL> select * from t where t.id=99;

在RBO的年代里,執行計劃是這樣的


select * from t where t.id=99

##首先執行SQL SQL> select /*+ rule */ * from t where id=99;ID OBJECT_NAME ---------- -------------------99 ICOL$##查找SQL對應的SQL_ID SQL>  SELECT sql_id, child_number, a.* from v$sql a where a.SQL_TEXT like '%select /*+ rule */ * from t where id=99%'; SQL_ID CHILD_NUMBER ------------- ------------ axszbzuk341sw 0##通過DBMS_XPLAN.display_cursor查詢執行計劃 SQL> select * from table(DBMS_XPLAN.display_cursor('axszbzuk341sw',0));


select * from t where t.id=1;

同樣的方式我們得出執行計劃

使用 hint /+ rule /的方式強制讓ORACLE使用RBO優化器來產生執行計劃,結果非常令人失望,不出所料,ORACLE在ID字段有索引的情況下,毫無懸念的全部選擇了索引。

實際上我們知道,對于id=1,幾乎所有的數據全都符合謂詞條件,選擇索引只能增加額外的開銷(因為ORACLE首先要訪問索引數據塊,在索引上找到了相應的鍵值,然后按照鍵值上的rowid 再去訪問表中相應的數據)。

既然我們幾乎要訪問所有表中的數據,那么全表掃描自然是最優的選擇,很遺憾RBO做出了錯誤的選擇。


CBO(Cost Based Optimizer)

CBO概述

從8i開始,ORACLE引入了CBO,它的思路是讓ORACLE獲取所有執行計劃相關的信息,通過對這些信息進行計算分析,最后得出一個代價最小的執行計劃作為最終的執行計劃。

CBO基于成本的優化器,其特點如下。

(1)依賴于數據對象的統計信息,例如表的記錄數、消耗的數據塊數、索引的可選性(不同的記錄值數量)等。

(2)使用精細的成本模型來評估SQL語句的執行性能。例如CPU消耗、邏輯讀寫(內存消耗)、I/O讀寫、網絡傳輸量的消耗分析等。

(3)語句優化的整體質量高于RBO。

(4)Oracle的大量新特性只能在CBO下運行。例如:HASH_JOIN操作、Bitmap索引、物化視圖等。

可見相比RBO,CBO是一種更加精確而有效的優化器。


案例說明

同樣是使用RBO中的案例,我們來看下CBO的表現。

##減少影響,先清空shared_Pool中的數據 SQL> alter system flush shared_pool;System altered ##對表做一次分析(cascade => true ,索引也會被一同分析) SQL> exec dbms_stats.gather_table_stats(user,'t',cascade => true);PL/SQL procedure successfully completed SQL>select /*+ all_rows */ * from t where t.id=1;SQL>SELECT sql_id, child_number, a.* from v$sql a where a.SQL_TEXT like '%select /*+ all_rows */ * from t where t.id=1%';SQL>select * from table(DBMS_XPLAN.display_cursor('d6adsf8y8c6mu',0));

SQL>select /*+ all_rows */ * from t where t.id=99;SQL>SELECT sql_id, child_number, a.* from v$sql a where a.SQL_TEXT like '%select /*+ all_rows */ * from t where t.id=99%';SQL>select * from table(DBMS_XPLAN.display_cursor('8w6r8hzrkunnu',0));

可以看出 CBO表現的非常完美,

  • id=1 全表掃描 TABLE ACCESS FULL
  • id=99 索引掃描 INDEX RANGE SCAN

因為這樣的選擇代價是最小的,為了驗證CBO選擇的正確性,我們分別讓這兩條SQL各自做一次全表掃描和和選擇索引。


全表掃描

select * from t where id=1; Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing optionsSQL> alter session set tracefile_identifier='mytest';Session altered.SQL> alter session set sql_trace=true;Session altered.SQL> select * from t where id=1; ....... 35251 rows selected.SQL> alter session set sql_trace=false;Session altered. SQL> select name, value from v$parameter where name = 'user_dump_dest';NAME VALUE ------------ ---------- user_dump_dest /oracle/diag/rdbms/cc/cc/trace

ORACLE主機上查看

oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$ls *mytest* cc_ora_8752_mytest.trc cc_ora_8752_mytest.trm

tkprof 工具匯總分析

oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$tkprof cc_ora_8752_mytest.trc mytest.txt sys=no explain=xxx/xgjTKPROF: Release 11.2.0.4.0 - Development on Tue Dec 27 23:24:32 2016Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

截取部分關鍵信息:


索引掃描

select /*+ index(t IDX_T) */* from t where id=1; SQL> alter session set tracefile_identifier='index_scan';Session alteredSQL> alter session set sql_trace=true;Session alteredSQL> select /*+ index(t IDX_T) */* from t where id=1; ....... 35251 rows selected.SQL> alter session set sql_trace=false;Session altered.

獲取到trc原文件后,使用tkprof分析匯總

oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$tkprof cc_ora_8709_index_scan.trc index_scan.txt explain=xxx/xgj sys=noTKPROF: Release 11.2.0.4.0 - Development on Tue Dec 27 23:35:57 2016Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

截取關鍵信息:

比較:

select * from t where id=1;--全表掃描了2470個數據塊 select /*+ index(t IDX_T) */* from t where id=1;--索引掃描了4892個數據塊

顯然這種情況下,CBO的選擇是正確的,使用全表掃描的效率更高,速度更快。


同樣的方式我們比較下

select * from t where id=99; select /*+ full(t) */ * from t where id=99;

select * from t where id=99;

Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 Connected as xxx@xgjSQL> alter session set tracefile_identifier='full_scan';Session alteredSQL> alter session set sql_trace=true;Session alteredSQL> select * from t where id=99;ID OBJECT_NAME ---------- ------------------------99 ICOL$SQL> alter session set sql_trace=false;Session alteredSQL>

在oracle主機上使用tkprof分析匯總

[root@entel1 ~]# su - oracle oracle@entel1:[/oracle]$cd /oracle/diag/rdbms/cc/cc/trace oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$ls *full* cc_ora_16197_full_scan.trc cc_ora_16197_full_scan.trm oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$tkprof cc_ora_16197_full_scan.trc full_scan.txt explain=zmc/smart sys=noTKPROF: Release 11.2.0.4.0 - Development on Wed Dec 28 23:41:24 2016Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$cat full_scan.txt

部分關鍵信息如下:


采用同樣的方式我們分析下
select /+ full(t) / * from t where id=99;


通過對比上述的執行計劃,選擇索引的只掃描了3個數據塊,而全表掃描則掃描了135個數據塊,再此證明了CBO選擇的正確性。


從ORACLE10g開始,ORACLE已經徹底丟棄了RBO。
即使在表索引沒有被分析的時候,Oracle依然會使用CBO,此時,ORACLE會使用一種叫做動態采樣的技術,在分析SQL的時候,動態的搜集表、索引上的一些數據塊,使用這些數據塊的信息及字典表中關于這些對象的信息來計算出執行計劃的代價,從而挑選出最優的執行計劃。

舉例說明:

SQL> drop table t ;Table droppedSQL> create table t (x int ,y varchar2(2000));Table createdSQL> insert into t select object_id ,object_name from dba_objects;35254 rows insertedSQL> commit;Commit completeSQL> create index idx_t on t(x);Index createdSQL> alter session set tracefile_identifier='xgj_test';Session alteredSQL> alter session set sql_trace=true;Session alteredSQL> select count(1) from t where x<100;COUNT(1) ----------98SQL> alter session set sql_trace=false;Session altered##查看SQL_ID SQL> SELECT sql_id, child_number, a.* from v$sql a where a.SQL_TEXT like '% select count(1) from t where x<100%'; ##根據SQL_ID查看執行計劃 SQL>select * from table(DBMS_XPLAN.display_cursor('5yk2jzsm7cpnh',0));

如下:


可以看到,當表沒有做分析的時候,ORACLE 會采用動態采樣來搜集統計信息,這個動作只發生在SQL執行的第一次,即硬分析階段使用,后續的軟分析將不再使用動態采樣,直接使用第一次SQL硬分析時生成的執行計劃。

同時我們也采集了SQL_TRACE的信息,我們使用tkprof分析匯總后來看下

TKPROF: Release 11.2.0.4.0 - Development on Thu Dec 29 00:00:16 2016Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.Trace file: cc_ora_16197_xgj_test.trc Sort options: default******************************************************************************** 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 ********************************************************************************SQL ID: 96ckjhxq51nwk Plan Hash: 0alter session set sql_trace=truecall 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 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 2 0.00 0.00 0 0 0 0Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: 38 (ZMC) ********************************************************************************SQL ID: gjz1ws759xbbp Plan Hash: 1807638002SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false') NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"), NVL(SUM(C2),:"SYS_B_1") FROM(SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T") FULL("T") NO_PARALLEL_INDEX("T") */ :"SYS_B_2" AS C1, CASE WHEN "T"."X"<:"SYS_B_3" THEN :"SYS_B_4" ELSE :"SYS_B_5" END AS C2 FROM "ZMC"."T" SAMPLE BLOCK (:"SYS_B_6" , :"SYS_B_7") SEED (:"SYS_B_8") "T") SAMPLESUBcall 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 1 0.00 0.00 0 69 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 3 0.00 0.00 0 69 0 1Misses in library cache during parse: 1 Misses in library cache during execute: 1 Optimizer mode: ALL_ROWS Parsing user id: 38 (ZMC) (recursive depth: 1) Number of plan statistics captured: 1Rows (1st) Rows (avg) Rows (max) Row Source Operation ---------- ---------- ---------- ---------------------------------------------------1 1 1 SORT AGGREGATE (cr=69 pr=0 pw=0 time=3244 us)11794 11794 11794 TABLE ACCESS SAMPLE T (cr=69 pr=0 pw=0 time=1955 us cost=2 size=525 card=21)error during execute of EXPLAIN PLAN statement ORA-00907: missing right parenthesisparse error offset: 493 ********************************************************************************SQL ID: 1pr6146q5bau5 Plan Hash: 3306840186SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS opt_param('parallel_execution_enabled','false') NO_PARALLEL(SAMPLESUB) NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"), NVL(SUM(C2),:"SYS_B_1"), NVL(SUM(C3),:"SYS_B_2")FROM(SELECT /*+ NO_PARALLEL("T") INDEX("T" IDX_T) NO_PARALLEL_INDEX("T") */ :"SYS_B_3" AS C1, :"SYS_B_4" AS C2, :"SYS_B_5" AS C3 FROM "ZMC"."T" "T" WHERE "T"."X"<:"SYS_B_6" AND ROWNUM <= :"SYS_B_7") SAMPLESUBcall 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 1 0.00 0.00 4 2 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 3 0.00 0.00 4 2 0 1Misses in library cache during parse: 1 Misses in library cache during execute: 1 Optimizer mode: ALL_ROWS Parsing user id: 38 (ZMC) (recursive depth: 1) Number of plan statistics captured: 1Rows (1st) Rows (avg) Rows (max) Row Source Operation ---------- ---------- ---------- ---------------------------------------------------1 1 1 SORT AGGREGATE (cr=2 pr=4 pw=0 time=301 us)98 98 98 VIEW (cr=2 pr=4 pw=0 time=318 us cost=33 size=390 card=10)98 98 98 COUNT STOPKEY (cr=2 pr=4 pw=0 time=216 us)98 98 98 INDEX RANGE SCAN IDX_T (cr=2 pr=4 pw=0 time=213 us cost=33 size=429 card=33)(object id 79508)Rows Execution Plan ------- ---------------------------------------------------0 SELECT STATEMENT MODE: HINT: ALL_ROWS1 SORT (AGGREGATE)98 VIEW98 COUNT (STOPKEY)98 INDEX MODE: ANALYZED (RANGE SCAN) OF 'IDX_T' (INDEX)上面的信息就是ORACLE做動態采樣的SQL語句。********************************************************************************SQL ID: 5yk2jzsm7cpnh Plan Hash: 1500240790select count(1) fromt where x<100call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 2 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 1 0.00 0.00 0 2 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 3 0.00 0.00 0 4 0 1Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: 38 (ZMC) Number of plan statistics captured: 1Rows (1st) Rows (avg) Rows (max) Row Source Operation ---------- ---------- ---------- ---------------------------------------------------1 1 1 SORT AGGREGATE (cr=2 pr=0 pw=0 time=43 us)98 98 98 INDEX RANGE SCAN IDX_T (cr=2 pr=0 pw=0 time=110 us cost=2 size=1274 card=98)(object id 79508)Rows Execution Plan ------- ---------------------------------------------------0 SELECT STATEMENT MODE: ALL_ROWS1 SORT (AGGREGATE)98 INDEX MODE: ANALYZED (RANGE SCAN) OF 'IDX_T' (INDEX)上面是SQL本身執行時的實際信息********************************************************************************OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTScall count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 2 0.00 0.00 0 2 0 0 Execute 2 0.00 0.00 0 0 0 0 Fetch 1 0.00 0.00 0 2 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 5 0.00 0.00 0 4 0 1Misses in library cache during parse: 2OVERALL TOTALS FOR ALL RECURSIVE STATEMENTScall count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 2 0.00 0.00 0 0 0 0 Execute 2 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 4 71 0 2 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 6 0.00 0.00 4 71 0 2Misses in library cache during parse: 2 Misses in library cache during execute: 24 user SQL statements in session.0 internal SQL statements in session.4 SQL statements in session.2 statements EXPLAINed in this session. ******************************************************************************** Trace file: cc_ora_16197_xgj_test.trc Trace file compatibility: 11.1.0.7 Sort options: default1 session in tracefile.4 user SQL statements in trace file.0 internal SQL statements in trace file.4 SQL statements in trace file.4 unique SQL statements in trace file.2 SQL statements EXPLAINed using schema:ZMC.prof$plan_tableDefault table was used.Table was created.Table was dropped.97 lines in trace file.37 elapsed seconds in trace file.

總結

以上是生活随笔為你收集整理的Oracle优化04-Optimizer优化器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。