溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

RBO和CBO的基本概念

發(fā)布時(shí)間:2020-08-07 13:28:26 來源:ITPUB博客 閱讀:130 作者:Thinkbase 欄目:關(guān)系型數(shù)據(jù)庫(kù)

轉(zhuǎn)自瀟湘隱者
出處:http://www.cnblogs.com/kerrycode/p/3842215.html

Oracle數(shù)據(jù)庫(kù)中的優(yōu)化器又叫查詢優(yōu)化器(Query Optimizer)。它是SQL分析和執(zhí)行的優(yōu)化工具,它負(fù)責(zé)生成、制定SQL的執(zhí)行計(jì)劃。Oracle的優(yōu)化器有兩種,基于規(guī)則的優(yōu)化器(RBO)與基于代價(jià)的優(yōu)化器(CBO)

         RBO: Rule-Based Optimization 基于規(guī)則的優(yōu)化器

         CBO: Cost-Based Optimization 基于代價(jià)的優(yōu)化器

RBO自O(shè)RACLE 6以來被采用,一直沿用至ORACLE 9i. ORACLE 10g開始,ORACLE已經(jīng)徹底丟棄了RBO,它有著一套嚴(yán)格的使用規(guī)則,只要你按照它去寫SQL語(yǔ)句,無(wú)論數(shù)據(jù)表中的內(nèi)容怎樣,也不會(huì)影響到你的“執(zhí)行計(jì)劃”,也就是說RBO對(duì)數(shù)據(jù)不“敏感”;它根據(jù)ORACLE指定的優(yōu)先順序規(guī)則,對(duì)指定的表進(jìn)行執(zhí)行計(jì)劃的選擇。比如在規(guī)則中,索引的優(yōu)先級(jí)大于全表掃描;RBO是根據(jù)可用的訪問路徑以及訪問路徑等級(jí)來選擇執(zhí)行計(jì)劃,在RBO中,SQL的寫法往往會(huì)影響執(zhí)行計(jì)劃,它要求開發(fā)人員非常了解RBO的各項(xiàng)細(xì)則,菜鳥寫出來的SQL腳本性能可能非常差。隨著RBO的被遺棄,漸漸不為人所知。也許只有老一輩的DBA對(duì)其了解得比較深入。關(guān)于RBO的訪問路徑,官方文檔做了詳細(xì)介紹:

RBO Path 1: Single Row by Rowid

RBO Path 2: Single Row by Cluster Join

RBO Path 3: Single Row by Hash Cluster Key with Unique or Primary Key

RBO Path 4: Single Row by Unique or Primary Key

RBO Path 5: Clustered Join

RBO Path 6: Hash Cluster Key

RBO Path 7: Indexed Cluster Key

RBO Path 8: Composite Index

RBO Path 9: Single-Column Indexes

RBO Path 10: Bounded Range Search on Indexed Columns

RBO Path 11: Unbounded Range Search on Indexed Columns

RBO Path 12: Sort Merge Join

RBO Path 13: MAX or MIN of Indexed Column

RBO Path 14: ORDER BY on Indexed Column

RBO Path 15: Full Table Scan

CBO是一種比RBO更加合理、可靠的優(yōu)化器,它是從ORACLE 8中開始引入,但到ORACLE 9i 中才逐漸成熟,在ORACLE 10g中完全取代RBO, CBO是計(jì)算各種可能“執(zhí)行計(jì)劃”的“代價(jià)”,即COST,從中選用COST最低的執(zhí)行方案,作為實(shí)際運(yùn)行方案。它依賴數(shù)據(jù)庫(kù)對(duì)象的統(tǒng)計(jì)信息,統(tǒng)計(jì)信息的準(zhǔn)確與否會(huì)影響CBO做出最優(yōu)的選擇。如果對(duì)一次執(zhí)行SQL時(shí)發(fā)現(xiàn)涉及對(duì)象(表、索引等)沒有被分析、統(tǒng)計(jì)過,那么ORACLE會(huì)采用一種叫做動(dòng)態(tài)采樣的技術(shù),動(dòng)態(tài)的收集表和索引上的一些數(shù)據(jù)信息。

關(guān)于RBO與CBO,我有個(gè)形象的比喻:大數(shù)據(jù)時(shí)代到來以前,做生意或許憑借多年累計(jì)下來的經(jīng)驗(yàn)(RBO)就能夠很好的做出決策,跟隨市場(chǎng)變化。但是大數(shù)據(jù)時(shí)代,如果做生意還是靠以前憑經(jīng)驗(yàn)做決策,而不是靠大數(shù)據(jù)、數(shù)據(jù)分析、數(shù)據(jù)挖掘做決策,那么就有可能做出錯(cuò)誤的決策。這也就是越來越多的公司對(duì)BI、數(shù)據(jù)挖掘越來越重視的緣故,像電商、游戲、電信等行業(yè)都已經(jīng)大規(guī)模的應(yīng)用,以前在一家游戲公司數(shù)據(jù)庫(kù)部門做BI分析,挖掘潛在消費(fèi)用戶簡(jiǎn)直無(wú)所不及。至今映像頗深。

CBO與RBO的優(yōu)劣

CBO優(yōu)于RBO是因?yàn)镽BO是一種呆板、過時(shí)的優(yōu)化器,它只認(rèn)規(guī)則,對(duì)數(shù)據(jù)不敏感。畢竟規(guī)則是死的,數(shù)據(jù)是變化的,這樣生成的執(zhí)行計(jì)劃往往是不可靠的,不是最優(yōu)的,CBO由于RBO可以從很多方面體現(xiàn)。下面請(qǐng)看一個(gè)例子,此案例來自于《讓Oracle跑得更快》。

 
SQL> create table test as select 1 id ,object_name from dba_objects;
 
Table created.
 
SQL> create index idx_test on test(id);
 
Index created.
 
SQL> update test set id=100 where rownum =1;
 
1 row updated.
 
SQL> select id, count(1) from test group by id;
 
        ID COUNT(1)
---------- ----------
       100          1
         1      50314

從上面可以看出,該測(cè)試表的數(shù)據(jù)分布極其不均衡,ID=100的記錄只有一條,而ID=1的記錄有50314條。我們先看看RBO下兩條SQL的執(zhí)行計(jì)劃.

SQL> select /*+ rule */ * from test where id =100;
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
 
------------------------------------------------
| Id  | Operation                   | Name     |
------------------------------------------------
|   0 | SELECT STATEMENT            |          |
|   1 | TABLE ACCESS BY INDEX ROWID| TEST     |
|*  2 | INDEX RANGE SCAN          | IDX_TEST |
------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"=100)
 
Note
-----
 - rule based optimizer used (consider using cbo)
 
 
Statistics
----------------------------------------------------------
 1  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
        588  bytes sent via SQL*Net to client
        469  bytes received via SQL*Net from client
          2 SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1 rows processed
 
SQL> 

 

SQL> select /*+ rule */ * from test where id=1;
 
50314 rows selected.
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
 
------------------------------------------------
| Id  | Operation                   | Name     |
------------------------------------------------
|   0 | SELECT STATEMENT            |          |
|   1 | TABLE ACCESS BY INDEX ROWID| TEST     |
|*  2 | INDEX RANGE SCAN          | IDX_TEST |
------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"=1)
 
Note
-----
 - rule based optimizer used (consider using cbo)
 
 
Statistics
----------------------------------------------------------
 1  recursive calls
          0  db block gets
       7012  consistent gets
         97  physical reads
          0  redo size
    2243353  bytes sent via SQL*Net to client
      37363  bytes received via SQL*Net from client
       3356 SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      50314 rows processed

 

從執(zhí)行計(jì)劃可以看出,RBO的執(zhí)行計(jì)劃讓人有點(diǎn)失望,對(duì)于ID=1,幾乎所有的數(shù)據(jù)全部符合謂詞條件,走索引只能增加額外的開銷(因?yàn)镺RACLE首先要訪問索引數(shù)據(jù)塊,在索引上找到了對(duì)應(yīng)的鍵值,然后按照鍵值上的ROWID再去訪問表中相應(yīng)數(shù)據(jù)),既然我們幾乎要訪問所有表中的數(shù)據(jù),那么全表掃描自然是最優(yōu)的選擇。而RBO選擇了錯(cuò)誤的執(zhí)行計(jì)劃??梢詫?duì)比一下CBO下SQL的執(zhí)行計(jì)劃,顯然它對(duì)數(shù)據(jù)敏感,執(zhí)行計(jì)劃及時(shí)的根據(jù)數(shù)據(jù)量做了調(diào)整,當(dāng)查詢條件為1時(shí),它走全表掃描;當(dāng)查詢條件為100時(shí),它走區(qū)間索引掃描。如下所示:

SQL> select * from test where id=1;
 
50314 rows selected.
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020
 
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 49075 |  3786K|    52   (2)| 00:00:01 |
|*  1 | TABLE ACCESS FULL| TEST | 49075 |  3786K|    52   (2)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("ID"=1)
 
Note
-----
 - dynamic sampling used for this statement
 
 
Statistics
----------------------------------------------------------
 32  recursive calls
          0  db block gets
       3644  consistent gets
          0  physical reads
          0  redo size
    1689175  bytes sent via SQL*Net to client
      37363  bytes received via SQL*Net from client
       3356 SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      50314 rows processed
 
SQL> select * from test where id =100;
 
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2473784974
 
----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |     1 |    79 |     2   (0)| 00:00:01 |
|   1 | TABLE ACCESS BY INDEX ROWID| TEST     |     1 |    79 |     2   (0)| 00:00:01 |
|*  2 | INDEX RANGE SCAN          | IDX_TEST |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"=100)
 
Note
-----
 - dynamic sampling used for this statement
 
 
Statistics
----------------------------------------------------------
 9  recursive calls
          0  db block gets
         73  consistent gets
          0  physical reads
          0  redo size
        588  bytes sent via SQL*Net to client
        469  bytes received via SQL*Net from client
          2 SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1 rows processed
 
SQL> 

僅此一項(xiàng)就可以看出為什么ORACLE極力推薦使用CBO,從ORACLE 10g開始不支持RBO的緣故。所謂長(zhǎng)江后浪推前浪,前浪死在沙灘上。

CBO知識(shí)點(diǎn)的總結(jié)

CBO優(yōu)化器根據(jù)SQL語(yǔ)句生成一組可能被使用的執(zhí)行計(jì)劃,估算出每個(gè)執(zhí)行計(jì)劃的代價(jià),并調(diào)用計(jì)劃生成器(Plan Generator)生成執(zhí)行計(jì)劃,比較執(zhí)行計(jì)劃的代價(jià),最終選擇選擇一個(gè)代價(jià)最小的執(zhí)行計(jì)劃。查詢優(yōu)化器由查詢轉(zhuǎn)換器(Query Transform)、代價(jià)估算器(Estimator)和計(jì)劃生成器(Plan Generator)組成。

CBO優(yōu)化器組件

CBO由以下組件構(gòu)成:

· 查詢轉(zhuǎn)化器(Query Transformer)

查詢轉(zhuǎn)換器的作用就是等價(jià)改變查詢語(yǔ)句的形式,以便產(chǎn)生更好的執(zhí)行計(jì)劃。它決定是否重寫用戶的查詢(包括視圖合并、謂詞推進(jìn)、非嵌套子查詢/子查詢反嵌套、物化視圖重寫),以生成更好的查詢計(jì)劃。

The input to the query transformer is a parsed query, which is represented by a set of
query blocks. The query blocks are nested or interrelated to each other. The form of the
query determines how the query blocks are interrelated to each other. The main
objective of the query transformer is to determine if it is advantageous to change the
form of the query so that it enables generation of a better query plan. Several different
query transformation techniques are employed by the query transformer, including:
■ View Merging
■ Predicate Pushing
■ Subquery Unnesting
■ Query Rewrite with Materialized Views
Any combination of these transformations can be applied to a given query.

· 代價(jià)評(píng)估器(Estimator)

評(píng)估器通過復(fù)雜的算法結(jié)合來統(tǒng)計(jì)信息的三個(gè)值來評(píng)估各個(gè)執(zhí)行計(jì)劃的總體成本:選擇性(Selectivity)、基數(shù)(Cardinality)、成本(Cost)

計(jì)劃生成器會(huì)考慮可能的訪問路徑(Access Path)、關(guān)聯(lián)方法和關(guān)聯(lián)順序,生成不同的執(zhí)行計(jì)劃,讓查詢優(yōu)化器從這些計(jì)劃中選擇出執(zhí)行代價(jià)最小的一個(gè)計(jì)劃。

· 計(jì)劃生成器(Plan Generator)

計(jì)劃生成器就是生成大量的執(zhí)行計(jì)劃,然后選擇其總體代價(jià)或總體成本最低的一個(gè)執(zhí)行計(jì)劃。

由于不同的訪問路徑、連接方式和連接順序可以組合,雖然以不同的方式訪問和處理數(shù)據(jù),但是可以產(chǎn)生同樣的結(jié)果

RBO和CBO的基本概念

下圖是我自己為了加深理解,用工具畫的圖

RBO和CBO的基本概念

 

查看ORACLE優(yōu)化器

SQL> show parameter optimizer_mode;
 
NAME                           TYPE VALUE
--------------------------- ----------- -----------------
optimizer_mode                 string      ALL_ROWS

RBO和CBO的基本概念

 

修改ORACLE優(yōu)化器

ORACLE 10g 優(yōu)化器可以從系統(tǒng)級(jí)別、會(huì)話級(jí)別、語(yǔ)句級(jí)別三種方式修改優(yōu)化器模式,非常方便靈活。

其中optimizer_mode可以選擇的值有: first_rows_n,all_rows.  其中first_rows_n又有first_rows_1000, first_rows_100, first_rows_10, first_rows_1

在Oracle 9i中,優(yōu)化器模式可以選擇first_rows_n,all_rows, choose, rule 等模式:

 

Rule: 基于規(guī)則的方式。

Choolse:指的是當(dāng)一個(gè)表或或索引有統(tǒng)計(jì)信息,則走CBO的方式,如果表或索引沒統(tǒng)計(jì)信息,表又不是特別的小,而且相應(yīng)的列有索引時(shí),那么就走索引,走RBO的方式。

If OPTIMIZER_MODE=CHOOSE, if statistics do not exist, and if you do not add hints to SQL statements, then SQL statements use the RBO. You can use the RBO to access both relational data and object types. If OPTIMIZER_MODE=FIRST_ROWS, FIRST_ROWS_n, or ALL_ROWS and no statistics exist, then the CBO uses default statistics. Migrate existing applications to use the cost-based approach.

First Rows:它與Choose方式是類似的,所不同的是當(dāng)一個(gè)表有統(tǒng)計(jì)信息時(shí),它將是以最快的方式返回查詢的最先的幾行,從總體上減少了響應(yīng)時(shí)間。

All Rows: 10g中的默認(rèn)值,也就是我們所說的Cost的方式,當(dāng)一個(gè)表有統(tǒng)計(jì)信息時(shí),它將以最快的方式返回表的所有的行,從總體上提高查詢的吞吐

雖然Oracle 10g中不再支持RBO,Oracle 10g官方文檔關(guān)于optimizer_mode參數(shù)的只有first_rows和all_rows.但是依然可以設(shè)置 optimizer_mode為rule或choose,估計(jì)是ORACLE為了過渡或向下兼容考慮。如下所示。

 

系統(tǒng)級(jí)別

SQL> alter system set optimizer_mode=rule scope=both;
 
System altered.
 
SQL> show parameter optimizer_mode
 
NAME                                 TYPE VALUE
-------------------------------- ----------- -----------------------
optimizer_mode                       string      RULE

RBO和CBO的基本概念

 

 

會(huì)話級(jí)別

會(huì)話級(jí)別修改優(yōu)化器模式,只對(duì)當(dāng)前會(huì)話有效,其它會(huì)話依然使用系統(tǒng)優(yōu)化器模式。

SQL> alter session set optimizer_mode=first_rows_100;

Session altered.

 

語(yǔ)句級(jí)別

語(yǔ)句級(jí)別通過使用提示hints來實(shí)現(xiàn)。

SQL> select /*+ rule */ * from dba_objects where rownum <= 10;

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI