文檔結構:html
oracle執行計劃使用場景sql
環境:數據庫
Centos 6.10c#
Oracle 18.3.0.0.0 csession
11g默認啓動了自動統計信息收集的任務,默認運行時間是週一到週五晚上10點和周6,周天的早上6點,這種自動收集統計信息的方式並非收集全部對象的統計信息,而是收集沒有統計信息的對象和統計信息過舊的對象。而後肯定優先級,再開始進行統計信息。oracle
Job 名稱是GATHER_STATS_JOB, 該Job收集數據庫全部對象的2種統計信息:app
(1)Missing statistics(統計信息缺失)函數
(2)Stale statistics(統計信息陳舊)性能
以及對應的以下:測試
(1)對象的統計信息以前沒有收集過。
(2)當對象有超過10%的rows 被修改,此時對象的統計信息也稱爲stale statistics。好比說白天truncate表了或者進行delete 超過10%的行。
select window_name,
window_next_time,
autotask_status,
optimizer_stats
from DBA_AUTOTASK_WINDOW_CLIENTS;
select client_name,status from dba_autotask_client
where client_name='auto optimizer stats collection';
1. 統計信息默認狀況下是每晚10點半後收集,若是新建對象還沒來得級收集統計信息,
就採用動態採樣的方式。
2. 具體在set autotrace 跟蹤的執行計劃中,能夠看到相似:- dynamic sampling
used for this statement (level=2)
3. 除非你用相似/*+dynamic_sampling(t 0) */的HINT關閉這個動態採樣。
4. 在收集過統計信息後,Oracle就不會採用動態採樣。
注:建索引過程當中,默認會收集索引相關的統計信息。
set autotrace off
set linesize 1000
drop table t_sample purge;
create table t_sample as select * from dba_objects;
create index idx_t_sample_objid on t_sample(object_id);
select num_rows, blocks, last_analyzed from user_tables
where table_name = 'T_SAMPLE';
--建索引後,自動收集統計信息。
select index_name,
num_rows,
leaf_blocks,
distinct_keys,
last_analyzed
from user_indexes
where table_name = 'T_SAMPLE';
select * from t_sample where object_id=20;
能夠查看那個是動態採樣
exec dbms_stats.gather_table_stats(ownname => 'sys',tabname => 'T_SAMPLE',estimate_percent => 10,method_opt=> 'for all indexed columns',cascade=>TRUE) ;
set autotrace off
select num_rows, blocks, last_analyzed
from user_tables
where table_name = 'T_SAMPLE';
能夠查看到有最後一次統計信息收集的時間了。
如下是平時分區表印記分區索引,直方圖,統計信息收集的一些筆記:
--查看錶的狀況
select table_name,num_rows, blocks, empty_blocks, avg_space, chain_cnt, avg_row_len,last_analyzed from user_tables; --普通表
select * from user_tab_partitions;--分區表
select table_name,partition_name,subpartition_name,num_rows, blocks, empty_blocks, avg_space, chain_cnt, avg_row_len,last_analyzed from user_tab_subpartitions; --子分區
select table_name,
partitioning_type,
subpartitioning_type,
partition_count
from user_part_tables
where subpartitioning_type <> 'NONE'; --查看分區表中帶子分區的個數
--當前用戶下,某個分區的記錄數是平均記錄數的2倍以上
set linesize 266
col table_name format a20
select table_name,
max(num_rows),
trunc(avg(num_rows),0),
sum(num_rows),
trunc(max(num_rows) / sum(num_rows),2),
count(*)
from user_tab_partitions
group by table_name
having max(num_rows) / sum(num_rows) > 2 / count(*);
--查看有子分區的數據狀況:
select table_name,partition_name,subpartition_name,
num_rows
--索引列的統計信息
BLEVEL, --索引的層數
LEAF_BLOCKS, --葉子結點的個數
DISTINCT_KEYS, --惟一值的個數
AVG_LEAF_BLOCKS_PER_KEY, --每一個KEY的平均葉塊個數
AVG_DATA_BLOCKS_PER_KEY, --每一個KEY的平均數據塊個數
CLUSTERING_FACTOR --羣集因子
select index_name,table_name,blevel, leaf_blocks, distinct_keys, avg_leaf_blocks_per_key,avg_data_blocks_per_key, clustering_factor from user_indexes; --普通表
select index_name,"COMPOSITE",SUBPARTITION_COUNT,PARTITION_NAME,blevel, leaf_blocks, distinct_keys, avg_leaf_blocks_per_key,avg_data_blocks_per_key, clustering_factor from user_ind_partitions --分區表
--查看普通索引失效:
select t.index_name,
t.table_name,
blevel,
t.num_rows,
t.leaf_blocks,
t.distinct_keys
from user_indexes t
where status = 'INVALID';
--查看分區索引失效:
select t.index_name,
t.table_name,
blevel,
t.num_rows,
t.leaf_blocks,
t.distinct_keys
from user_ind_subpartitions t
where index_name in (select index_name from user_indexes)
and status = 'INVALID'
--查看子分區索引
select t.index_name,
t.partition_name,
blevel,
t.num_rows,
t.leaf_blocks,
t.distinct_keys
from user_ind_subpartitions t
where index_name in (select index_name from user_indexes)
and status = 'INVALID'
分區表和子分區表
select index_name,PARTITION_NAME,SUBPARTITION_NAME,blevel,leaf_blocks,distinct_keys, avg_leaf_blocks_per_key,avg_data_blocks_per_key, clustering_factor from user_ind_subpartitions; --子分區表
查看直方圖:
SELECT table_name,column_name, num_distinct,low_value, high_value, density, num_nulls, num_buckets, histogram from user_tab_columns;
select * from user_tab_histograms;
select * from user_part_histograms;
select * from user_subpart_histograms;
查看列的信息:
NUM_DISTINCT, --惟一值的個數
LOW_VALUE, --列上的最小值
HIGH_VALUE, --列上的最大值
DENSITY, --選擇率因子(密度)
NUM_NULLS, --空值的個數
NUM_BUCKETS, --直方圖的BUCKET個數
HISTOGRAM --直方圖的類型
直方圖是一種列的特殊的統計信息,主要用來描述列上的數據分佈狀況,
SELECT table_name,column_name, num_distinct,low_value, high_value, density, num_nulls, num_buckets, histogram from user_tab_columns ;
直方圖:直方圖意義:在oracle數據庫中,CBO會默認認爲目標列的數據量在其最小值和最大值之間是均勻分佈的(最小值最大值不許確會致使謂詞越界),
而且會按照這個均勻分佈原則來計算對目標列事假的where查詢條件後的可選這率及結果集的cardinality,進而據此來計算成本值並選擇執行計劃。可是,目標列的數據是均勻分佈的按照這個原則選擇執行計劃是正確的;
若是目標數據列分佈不均勻,甚至是嚴重傾斜,分佈極度不均勻,那麼這個按照這個原則選擇執行計劃就不合適,甚至是錯誤的,爲此咱們須要對那些數據分佈不均勻的列進行直方圖收集。
直方圖實際存儲在數據字典sys.histgrm$中,能夠經過數據字典dba_tab_historgrams,dba_part_histograms和dba_subpart_histograms來分別查看錶,分區表的分區和分區表的子分區的直方圖信息。
收集統計信息的語句:
analyze 命令的語法以下:
analyze table tablename compute statistics;
analyze table tablename compute statistics for all indexes;
analyze table tablename delete statistics;
dbms_stats.gather_table_stats 收集表、列和索引的統計信息;
dbms_stats.gather_schema_stats 收集SCHEMA下全部對象的統計信息;
dbms_stats.gather_index_stats 收集索引的統計信息;
dbms_stats.gather_system_stats 收集系通通計信息
表統計信息的查看:
包含錶行數,使用的塊數,空的塊數,塊的使用率,行遷移和連接的數量,pctfree,pctused的數據,行的平均大小:
NUM_ROWS, --表中的記錄數
BLOCKS, --表中數據所佔的數據塊數
EMPTY_BLOCKS, --表中的空塊數
AVG_SPACE, --數據塊中平均的使用空間
CHAIN_CNT, --表中行鏈接和行遷移的數量
AVG_ROW_LEN --每條記錄的平均長度
統計信息的收集:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(ownname => 'hr',
tabname => 'employees',
estimate_percent => 100,
method_opt => 'for all columns size',
no_invalidate => FALSE,
degree => 1,
cascade => TRUE);
END;
/
刪除直方圖的影響:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'hr',
tabname => 'employees',
estimate_percent => 100,
method_opt => 'for all columns size 1',
no_invalidate => FALSE,
degree => 1,
cascade => TRUE);
END;
/
for all columns size 1 爲全部size 放在一個桶裏面(即爲刪除)
select a.table_name,a.column_name,
b.num_rows,
a.num_distinct Cardinality,
round(a.num_distinct / b.num_rows * 100, 2) selectivity,
a.histogram,
a.num_buckets
from user_tab_col_statistics a, user_tables b
where
a.table_name = b.table_name
oracle 通常查詢數據行數在5%及如下,用到索引過略字段,CBO會走索引
生成了直方圖以後 執行如下兩個句子查看一下分別的執行計劃對比看看
NUM_ROWS 表示總行數
CARDINALITY 表示基數
SELECTIVITY表示選擇性 選擇性在10%以上都比較高了
HISTOGRAM表示直方圖的類型:
FREQUECNCY頻率直方圖、 當列中Distinct_keys 較少(小於254),若是不手工指定直方圖桶數(BUCKET),Oracle就會自動的建立頻率直方圖,而且桶數(BUCKET)等於Distinct_Keys。
HEIGHT BALANCED 高度平衡直方圖 當列中Distinct_keys大於254,若是不手工指定直方圖桶數(BUCKET),Oracle就會自動的建立高度平衡直方圖。
NONE表示未收集直方圖
NUM_BUCKETS 表示桶數
三、疑問使用直方圖的場合
一、直方圖到底應該何時收集直方圖?
就查一下執行計劃和實際查詢行數進行比較 估算的基數ROWS是否是算錯了。
構造直方圖最主要的緣由就是幫助優化器在表中數據嚴重偏斜時作出更好的規劃
注意:若是查詢不引用該列,則建立直方圖沒有意義。這種錯誤很常見,許多 DBA 會在誤差列上建立柱狀圖,即便沒有任何查詢引用該列。
二、只對有索引的列收集直方圖也是錯的!
三、直方圖到底是幹嗎的?
告訴CBO 有沒有收集直方圖 這個列是否是均衡的
1. 沒收集直方圖 ---CBO認爲這個列是分佈均勻的
2. 收集過了 ---告訴CBO這個列數據有問題 分佈不均衡,特別是頻率直方圖算的會很準
最終就是影響rows
獲取執行計劃的6種方法
1. explain plan for獲取
2. set autotrace on
3. statistics_level=all
4. 經過dbms_xplan.display_cursor輸入sql_id參數直接獲取
5. 10046 trace跟蹤
6. awrsqrpt.sql
相似PLSQL DEVELOPER裏的F5
/*
步驟1:explain plan for "你的SQL"
步驟2:select * from table(dbms_xplan.display());
*/
set linesize 1000
set pagesize 2000
explain plan for
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
select * from table(dbms_xplan.display());
優勢: 1.無需真正執行,快捷方便
缺陷: 1.沒有輸出運行時的相關統計信息(產生多少邏輯讀,多少次遞歸調用,多少次物理讀的狀況);
2.沒法判斷是處理了多少行;
3.沒法判斷表被訪問了多少次。
確實啊,這畢竟都沒有真正執行又如何得知真實運行產生的統計信息。
有以下幾種方式:
set autotrace on (獲得執行計劃,輸出運行結果)
set autotrace traceonly (獲得執行計劃,不輸出運行結果)
set autotrace traceonly explain (獲得執行計劃,不輸出運行結果和統計信息部分,僅展示執行計劃部分)
set autotrace traceonl statistics(不輸出運行結果和執行計劃部分,僅展示統計信息部分)
set autotrace on
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
優勢:1.能夠輸出運行時的相關統計信息(產生多少邏輯讀,多少次遞歸調用,多少次物理讀的狀況);
2.雖然必需要等語句執行完畢後才能夠輸出執行計劃,可是能夠有traceonly開關來控制返回結果不打屏輸出。
步驟1:alter session set statistics_level=all ;
步驟2:在此處執行你的SQL
步驟3:select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
set autotrace off
alter session set statistics_level=all ;
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
另注:
1. 若是你用 /*+ gather_plan_statistics */的方法,能夠省略步驟1,直接步驟2,3。
2. 關鍵字解讀(其中OMem、1Mem和User-Mem在後續的課程中會陸續見到):
Starts爲該sql執行的次數。
E-Rows爲執行計劃預計的行數。
A-Rows爲實際返回的行數。A-Rows跟E-Rows作比較,就能夠肯定哪一步執行計劃出了問題。
A-Time爲每一步實際執行的時間(HH:MM:SS.FF),根據這一行能夠知道該sql耗時在了哪一個地方。
Buffers爲每一步實際執行的邏輯讀或一致性讀。
Reads爲物理讀。
OMem:當前操做完成全部內存工做區(Work Aera)操做所總共使用私有內存(PGA)中工做區的大小,
這個數據是由優化器統計數據以及前一次執行的性能數據估算得出的
1Mem:當工做區大小沒法知足操做所需的大小時,須要將部分數據寫入臨時磁盤空間中(若是僅須要寫入一次就能夠完成操做,
就稱一次經過,One-Pass;不然爲屢次經過,Multi_Pass).該列數據爲語句最後一次執行中,單次寫磁盤所須要的內存
大小,這個由優化器統計數據以及前一次執行的性能數據估算得出的
User-Mem:語句最後一次執行中,當前操做所使用的內存工做區大小,括號裏面爲(發生磁盤交換的次數,1次即爲One-Pass,
大於1次則爲Multi_Pass,若是沒有使用磁盤,則顯示OPTIMAL)
OMem、1Mem爲執行所需的內存評估值,0Mem爲最優執行模式所需內存的評估值,1Mem爲one-pass模式所需內存的評估值。
0/1/M 爲最優/one-pass/multipass執行的次數。Used-Mem耗的內存
--優勢:1.能夠清晰的從STARTS得出表被訪問多少。
2.能夠清晰的從E-ROWS和A-ROWS中獲得預測的行數和真實的行數,從而能夠準確判斷Oracle評估是否準確。
3.雖然沒有專門的輸出運行時的相關統計信息,可是執行計劃中的BUFFERS就是真實的邏輯讀的多少
--缺陷:1.必需要等到語句真正執行完畢後,才能夠出結果。
2.沒法控制記錄輸屏打出,不像autotrace有 traceonly 能夠控制不將結果打屏輸出。
3.看不出遞歸調用的次數,看不出物理讀的多少(不過邏輯讀纔是重點)
select * from table(dbms_xplan.display_cursor('&sq_id')); (該方法是從共享池裏獲得)
注:
1. 還有一個方法,select * from table(dbms_xplan.display_awr('&sq_id'));(這是awr性能視圖裏獲取到的)
2. 若是有多執行計劃,能夠用相似方法查出
先經過v$sql查看sql_id:
select * from table(dbms_xplan.display_cursor('1a914ws3ggfsn',0));
select * from table(dbms_xplan.display_cursor('1a914ws3ggfsn',1));
這個好處就是能夠查看該sql多個執行計劃
從中能夠看出:
--優勢:1.知道sql_id當即可獲得執行計劃,和explain plan for 同樣無需執行;
2.能夠獲得真實的執行計劃。(停,等等,啥真實的,剛纔這幾個套路中,還有假的執行計劃的嗎?)
--缺陷 1.沒有輸出運行時的相關統計信息(產生多少邏輯讀,多少次遞歸調用,多少次物理讀的狀況);
2.沒法判斷是處理了多少行;
3.沒法判斷表被訪問了多少次。
(10046TRACE)
步驟1:alter session set events '10046 trace name context forever,level 12'; (開啓跟蹤)
步驟2:執行你的語句
步驟3:alter session set events '10046 trace name context off'; (關閉跟蹤)
步驟4:找到跟蹤後產生的文件
步驟5:tkprof trc文件 目標文件 sys=no sort=prsela,exeela,fchela (格式化命令)
set autotrace off
alter session set statistics_level=typical;
alter session set events '10046 trace name context forever,level 12';
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
alter session set events '10046 trace name context off';
12c以前查看trace文件:
select d.value
|| '/'
|| LOWER (RTRIM(i.INSTANCE, CHR(0)))
|| '_ora_'
|| p.spid
|| '.trc' trace_file_name
from (select p.spid
from v$mystat m,v$session s, v$process p
where m.statistic#=1 and s.sid=m.sid and p.addr=s.paddr) p,
(select t.INSTANCE
FROM v$thread t,v$parameter v
WHERE v.name='thread'
AND(v.VALUE=0 OR t.thread#=to_number(v.value))) i,
(select value
from v$parameter
where name='user_dump_dest') d;
12c以後 查看trace文件:
select d.value
|| '/'
|| LOWER (RTRIM(i.INSTANCE, CHR(0)))
|| '_ora_'
|| p.spid
|| '.trc' trace_file_name
from (select p.spid
from v$mystat m,v$session s, v$process p
where m.statistic#=1 and s.sid=m.sid and p.addr=s.paddr) p,
(select t.INSTANCE
FROM v$thread t,v$parameter v
WHERE v.name='thread'
AND(v.VALUE=0 OR t.thread#=to_number(v.value))) i,
(select value from v$diag_info where name='Diag Trace') d;
exit
tkprof /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_17496.trc /home/oracle/10046.txt
more /home/oracle/10046.txt
TKPROF: Release 18.0.0.0.0 - Development on Sat Oct 12 14:48:05 2019
Copyright (c) 1982, 2018, Oracle and/or its affiliates. All rights reserved.
Trace file: /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_17496.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
********************************************************************************
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19)
call 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 2 0.00 0.00 0 14 0 2
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 14 0 2
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
2 2 2 HASH JOIN (cr=14 pr=0 pw=0 time=474 us starts=1 cost=8 size=250 card=2)
2 2 2 NESTED LOOPS (cr=14 pr=0 pw=0 time=467 us starts=1 cost=8 size=250 card=2)
2 2 2 NESTED LOOPS (cr=12 pr=0 pw=0 time=584 us starts=1 cost=8 size=250 card=2)
2 2 2 STATISTICS COLLECTOR (cr=7 pr=0 pw=0 time=434 us starts=1)
2 2 2 INLIST ITERATOR (cr=7 pr=0 pw=0 time=395 us starts=1)
2 2 2 TABLE ACCESS BY INDEX ROWID BATCHED T1 (cr=7 pr=0 pw=0 time=391 us starts=2 cost=4 size=118 car
d=2)
2 2 2 INDEX RANGE SCAN T1_N (cr=5 pr=0 pw=0 time=347 us starts=2 cost=2 size=0 card=2)(object id 741
71)
2 2 2 INDEX RANGE SCAN T2_T1_ID (cr=5 pr=0 pw=0 time=147 us starts=2 cost=1 size=0 card=1)(object id 74
172)
2 2 2 TABLE ACCESS BY INDEX ROWID T2 (cr=2 pr=0 pw=0 time=35 us starts=2 cost=2 size=66 card=1)
0 0 0 TABLE ACCESS FULL T2 (cr=0 pr=0 pw=0 time=0 us starts=0 cost=2 size=66 card=1)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Disk file operations I/O 1 0.00 0.00
SQL*Net message to client 2 0.00 0.00
SQL*Net message from client 2 7.36 7.36
********************************************************************************
SQL ID: 06nvwn223659v Plan Hash: 0
alter session set events '10046 trace name context off'
call 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 0
Misses in library cache during parse: 0
Parsing user id: SYS
********************************************************************************
OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS
call 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 0 14 0 2
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 6 0.00 0.00 0 14 0 2
Misses in library cache during parse: 0
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Disk file operations I/O 2 0.00 0.00
SQL*Net message to client 3 0.00 0.00
SQL*Net message from client 3 7.36 14.08
OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 0 0.00 0.00 0 0 0 0
Execute 0 0.00 0.00 0 0 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 0 0.00 0.00 0 0 0 0
Misses in library cache during parse: 0
2 user SQL statements in session.
0 internal SQL statements in session.
2 SQL statements in session.
********************************************************************************
Trace file: /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_17496.trc
Trace file compatibility: 12.2.0.0
Sort options: default
1 session in tracefile.
2 user SQL statements in trace file.
0 internal SQL statements in trace file.
2 SQL statements in trace file.
2 unique SQL statements in trace file.
66 lines in trace file.
7 elapsed seconds in trace file.
--優勢:1.能夠看出SQL語句對應的等待事件(這個是level 12,0,4,8對應的是其餘狀況)
2.若是SQL語句中有函數調用,SQL中有SQL,將會都被列出,無處遁形。
3.能夠方便的看出處理的行數,產生的物理邏輯讀。
4.能夠方便的看出解析時間和執行時間。
5.能夠跟蹤整個程序包
--缺陷: 1.步驟繁瑣,比較麻煩
2.沒法判斷表被訪問了多少次。
3.執行計劃中的謂詞部分不能清晰的展示出來。
步驟1:@?/rdbms/admin/awrsqrpt.sql
步驟2:選擇你要的斷點(begin snap 和end snap)
步驟3:輸入你的sql_id
6種方法各自適用場合
1.若是某SQL執行很長時間纔出結果戒返回丌告終果,這時就只能用方法1;
2.跟蹤某條SQL最簡單的方法是方法1,其次就是方法2;
3.若是想觀察到某條SQL有多條執行計劃的狀況,只能用方法4和方法6;
4.若是SQL中含有函數,函數中套有SQL等多層調用,想準確分析只能使用方法5;
5.要想確保看到真實的執行計劃,丌能用方法1和方法2;
6.要想獲取表被訪問的次數,只能使用方法3;
執行計劃中"真實執行計劃」 是一個很重要的常識,這也就是方法1 和方法2 的最大缺陷了。 狠狠揪出本次即將被批鬥的壞蛋:方法1的explain plan for和方法2的set autotrace on
例子主要是針對:綁定變量窺視與直方圖
---構建T表,數據,及主鍵
---構建T表,數據,及主鍵
DROP TABLE t;
CREATE TABLE t
AS
SELECT rownum AS id, rpad('*',100,'*') AS pad
FROM dual
CONNECT BY level <= 1000;
ALTER TABLE t ADD CONSTRAINT t_pk PRIMARY KEY (id);
---收集統計信息
BEGIN
dbms_stats.gather_table_stats(
ownname => user,
tabname => 'T',
estimate_percent => 100,
method_opt => 'for all columns size 254'
);
END;
/
下面咱們將會用多種方法來查看以下語句的執行計劃
VARIABLE id NUMBER
COLUMN sql_id NEW_VALUE sql_id
EXECUTE :id := 990;
SELECT count(pad) FROM t WHERE id < :id;
EXECUTE :id := 10;
SELECT count(pad) FROM t WHERE id < :id;
利用以上6中方法查看執行計劃是否真實:
set linesize 1000
set pagesize 2000
VARIABLE id NUMBER
COLUMN sql_id NEW_VALUE sql_id
EXECUTE :id := 990;
explain plan for
SELECT count(pad) FROM t WHERE id < :id;
select * from table(dbms_xplan.display());
走的是索引範圍掃描
set autotrace traceonly
VARIABLE id NUMBER
COLUMN sql_id NEW_VALUE sql_id
EXECUTE :id := 990;
SELECT count(pad) FROM t WHERE id < :id;
也是索引範圍掃描
set autotrace off
alter session set statistics_level=all ;
VARIABLE id NUMBER
COLUMN sql_id NEW_VALUE sql_id
EXECUTE :id := 990;
SELECT count(pad) FROM t WHERE id < :id;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
看到沒有,全表掃描。
select * from table(dbms_xplan.display_cursor('asth1mx10aygn'));
也是全表掃描
set autotace off
alter session set statistics_level=typical;
alter session set events '10046 trace name context forever,level 12';
VARIABLE id NUMBER
COLUMN sql_id NEW_VALUE sql_id
EXECUTE :id := 990;
SELECT count(pad) FROM t WHERE id < :id;
alter session set events '10046 trace name context off';
12c以後 查看trace文件:
select d.value
|| '/'
|| LOWER (RTRIM(i.INSTANCE, CHR(0)))
|| '_ora_'
|| p.spid
|| '.trc' trace_file_name
from (select p.spid
from v$mystat m,v$session s, v$process p
where m.statistic#=1 and s.sid=m.sid and p.addr=s.paddr) p,
(select t.INSTANCE
FROM v$thread t,v$parameter v
WHERE v.name='thread'
AND(v.VALUE=0 OR t.thread#=to_number(v.value))) i,
(select value from v$diag_info where name='Diag Trace') d;
查看轉換的文件:
也是全表掃描
執行計劃中"一條SQL對應多個計劃」 也是一個很重要的常識,這隻能靠方法4和方法6了。
方法4的dbms_xplan.display_cursor+sql_id和方法6的awrsqrpt.sql
sys用戶登陸測試(切換了pdb):
DROP TABLE t;
CREATE TABLE t AS SELECT * FROM DBA_OBJECTS where object_id is not null;
create index idx_object_id on t(object_id);
alter table T modify object_id not null;
set autotrace off
set linesize 1000
set pagesize 2000
alter session set statistics_level=all ;
select count(*) from t;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
C##test用戶登陸測試(切換了pdb):
drop table t purge;
CREATE TABLE t AS SELECT rownum id ,rownum+1 n FROM DBA_OBJECTS ;
set autotrace off
set linesize 1000
set pagesize 2000
alter session set statistics_level=all ;
select count(*) from t;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
能夠查看是有兩個(貌似pdb裏面查詢結果不對)
select sql_id, child_number from v$sql where sql_id='cyzznbykb509s';
SQL_ID CHILD_NUMBER
------------- ------------
cyzznbykb509s 0
cyzznbykb509s 1
特別說明一下,第6種獲取執行計劃的方法awrsqrpt.sql一樣也能夠獲取到多條執行計劃
這個方法當一條SQL有多個執行計劃的時候,能夠在報表裏輸出。可是要確保在AWR的採集週期內的生成報表。
原文出處:https://www.cnblogs.com/hmwh/p/11685541.html