SQL優化之優化器

RBO 所有規則爲一組內置的規則,這些規則是硬編碼在oracle數據庫代碼中的
具體有規則:oracle在代碼裏事先給各個類型的執行路徑定了一個級別,一共15級,oracle認爲等級值低的比等級值高的執行效率要高;
當有兩條以上執行路徑等級相同時,可以通過調整相關對象在數據字典中的緩存順序來影響RBO對於執行計劃的選擇;RBO按照從右到左的順序來決定誰是驅動表誰是被驅動表
執行計劃一旦出現問題,很難對其做調整(不能使用索引)一般是等價改寫sql;目標sql涉及的各個對象的順序可能對sql執行計劃有影響;oracle很多好的特性不支持RBO
不支持CBO的情況:
目標sql中涉及的對象有IOT或者分區表;使用了並行查詢或者並行DML;使用了星形連接或者hash連接;使用了索引快速掃描;使用了函數索引等等
create table emp_temp as select * from emp;
 create index idx_mgr_temp on emp_temp(mgr);
 create index idx_deptno_temp on emp_temp(deptno);
alter session set optimizer_mode='RULE';
set autotrace traceonly explain
 select * from emp_temp where mgr>100 and deptno>100;
------------------------------------------------------------
CRB 所有的判斷原則爲成本,選擇成本最小的執行計劃,各執行計劃的成本是根據目標sql語句涉及的表、索引、列等相關統計信息計算出來的
概念:
集的勢/cardinality   集合所包含的記錄數(其實就是結果集的行數)   值越大所對應的成本值往往也越大
可選擇率/selectivity   施加指定謂詞條件後返回的結果集的記錄佔未施加任何謂詞條件的原始結果集的記錄數的比率 可選擇率越大返回的結果集就越大,估算出來的成本也就越大
可傳遞性  對目標sql做簡單的等價改寫,提供更多的執行路徑。增肌得到高效執行計劃的可能性
CBO的侷限性:
1、默認sql語句的where條件的列之間是獨立的沒有關聯關係——可使用動態採樣的準確性或者多列統計信息規避;但是動態採樣的準確性取決於採樣數據的質量和採樣數據的數量;而多列統計信息
不適用與有關聯關係的情形;
2、假設所有的目標sql都是單獨執行的並且互不干擾   ————沒有考慮緩存的影響
3、CBO對直方圖統計信息有限制:
a.12c之前頻率直方圖對於的桶不能超過254,超過就會使用平衡直方圖(統計不精確)
b.對文本型字段文本值的頭32字節取出來做統計信息存儲在數據字典中
4、在解析多表關聯的目標sql時,可能會漏選正確的執行計劃
------------------------------------------------------------------
優化器的模式:
1、RULE  表示使用RBO來解析目標sql
2、CHOOSE     目標sql所涉及的表均沒有統計信息就使用RBO,只要所涉及的目標sql的表有一個有統計信息就使用CBO
3、FIRST_ROW_n   以最快的響應速度返回頭n條記錄(此執行計劃的成本值會被修改一個很小的值)
4、FIRST_ROWS  聯合使用RBO和CBO,在特定的情況下使用RBO(比如使用索引來避免排序)
5、ALL_ROWS   使用CBO來解析sql 側重點在最佳的吞吐量
---------------------------------------------------------
訪問數據的方法
1、訪問表的方法             
a.全表掃描  執行時間不穩定、不可控隨數據量遞增而增加
b.ROWID 掃描(用戶輸入rowid或者訪問索引得到的rowid)
2、訪問索引的方法    B樹索引是自平衡的,走索引訪問數據的時間是可控的、基本穩定的、這也是走索引和全表掃描的最大區別
a.索引唯一性掃描 適用於where條件是等值查詢的目標sql,掃描的對象時唯一索引
b.索引範圍掃描 適用於所有的B樹索引
c.索引全掃描 適用於所有B樹索引 執行結果是有序的並且是按照索引鍵值列來排序的 不需要回表  (前提條件是目標索引至少有一個索引鍵值列的屬性是not null)
d.索引快速全掃描 適用於所有B樹索引
e.索引跳躍式掃描 適用於所有複合B樹索引 where條件中沒有對目標索引的前導列指定查詢條件但同時又對該索引的非前導列指定查詢條件的目標sql依然可以使用上該索引
 (相當於對目標sql做等價改寫)僅適用於前導列的distinct值數量較少、後續非前導列的可選擇性又非常好的情形
------------------索引全掃描月索引快速掃描的區別---------------------------
索引快速掃描只適用於CBO
索引快速掃描可以使用多塊讀,也可以並行執行
索引快速掃描的結果不一定是有序的(根據索引行在磁盤上的物理順序來掃描)
-------------------------------
表連接
表連接的類型 :1.內連接(自然連接的連接列是表連接的兩個表所有的同名列)
 2.外連接
表連接的方法:
1、排序合併連接
優缺點及適用場景——
a.排序合併連接效率遠不如hash連接,但排序合併連接使用範圍廣;hash連接只適用等值連接;
b.排序合併連接不適合OLTP系統,因爲排序在OLTP系統非常昂貴;如果能避免排序還是適合於OLTP系統的,例如兩表都有索引實際並不需要排序
2、嵌套循環連接
優缺點及適用場景——
a.適用於驅動表結果集小,被驅動表有索引(唯一索引或者選擇性很好的非唯一性索引)
b.嵌套循環可以快速響應;排序合併要等到排完序後做合併操作時才能開始返回,hash連接要等到驅動結果集所對應的hash table全部建完後才能開始返回
c.向量IO實現了在單塊讀不降低的情況下減少這些單塊讀所需要耗費的物理IO數量,從而提高嵌套循環連接的執行效率
3、hash連接
優缺點級適用場景——
a.hash連接不一定會排序,或者說大多數情況下都不需要排序
b.hash連接的驅動結果集所對應的連接列的可選擇性應儘可能好
c.hash連接只適用於CBO ,也只能適用於等值連接
d.hash連接很適合小表和大表直接做連接且連接結果集的記錄較多的情形,特別是小表的連接列的可選擇性非常好的情況下,執行時間可以近似看做是和全表掃描那個大表所耗費的時間相當
e.hash連接時 施加了目標sql中指定的謂詞條件後得到的數據量小的結果集所對應的hash table 能夠完全容納在PGA工作區中,此時hash連接的執行效率會非常高
4、笛卡爾連接
優缺點及適用場景——
a.通常是因爲目標sql漏寫了表連接條件,笛卡爾積一般是不好的,出發刻意這麼做
b.有時候是目標sql中使用了ORDERED HINT ,同時在該SQL的SQL文本中位置相鄰的兩個表之間有沒有直接的關聯條件
c.有時候是因爲目標SQL中相關表的統計信息不準
-----------------------------------------------------------
反連接:適用謂詞條件 not in、<> all 、not exists
半連接:適用謂詞條件 in 、= any 、exists
星形連接: 適用於數據倉庫
 
--------------------------------------------練習命令----------------------------------------------
create unique index idx_emp_temp on emp_temp(empno);
exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'EMP_TEMP',estimate_percent=>100,cascade=>true,method_opt=>'for all columns size 1',no_invalidate=>false);
exec dbms_stats.set_table_stats(ownname=>'SCOTT',tabname=>'EMP_TEMP',numrows=>10000000,no_invalidate=>false);
exec dbms_stats.set_index_stats(ownname=>'SCOTT',indname=>'IDX_MGR_TEMP',numlblks=>100000,no_invalidate=>false);
select empno,ename,rowid, dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid)||'_'||dbms_rowid.rowid_row_number(rowid) as loc from emp;
 select table_name,num_rows,blocks,to_char(last_analyzed,'yyyymmdd hh24:mi:ss') from dba_tables where table_name='EMP';
 select index_name,column_name,column_position from dba_ind_columns where table_name='EMP';
alter system flush shared_pool;
alter system flush buffer_cache;
alter table emp_test add constraint pk_emp_test primary key (empno,col1,col2,col3);
select /*+ index_ffs(emp_test pk_emp_test) */empno from emp_test;
select /*+ ordered use_nl(t2) */t1.c1,t1.c2,t2.c2 from t1,t2 where t1.c1=t2.c1;
select /*+ optimizer_features_enable('9.2.0') ordered use_nl(t2) */t1.c1,t1.c2,t2.c2 from t1,t2 where t1.c1=t2.c1;
SQL> set linesize 800
SQL> set pagesize 900
SQL> select * from t1 where not exists (select null from t2 where c1=t1.c1);
SQL> select * from t1 where c1 <> all(select c1 from t2);
SQL> select * from t1 where c1 not in (select c1 from t2);
------------------------
SQL> oradebug setmyid
oradebug event 10104 trace name context forever ,level 1
select /*+ ordered use_hash(t2) */t1.c1,t1.c2,t2.c2 from scott.t1,scott.t2 where t1.c1=t2.c1;
oradebug tracefile_name
-------------------------------
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章