文档结构: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