查看执行计划的方法:
这种方式看到的执行计划不必定是真实的,目前很少用了:
explain plan for select * from tab;
select * from table(dbms_xplan.display());
这种会执行SQL:
set autotrace on
select * from tab where rownum<1;
这种不会执行SQL:
set autotrace traceonly exp
select * from tab where rownum<10;
这种是最真实的执行计划:
alter session set sql_trace=true;
select * from tab where rownum<10;
alter session set sql_trace=false;
用 ls -lt | head 来查找生成的文件
用tkprof来解读文件
last_call_et:表明会话目前已经执行了多长时间,单位是秒
select sql_id,program,username,last_call_et from v$session where type != BACKGROUND and status= ACTIVE ;
select * from table(dbms_xplan.display_cursor( gvg0yjnt9dk6f ,null));
获取某个SQL的sql_id:
select sql_id from v$sql where sql_text like select count(*) from dba_objects ;
select * from table(dbms_xplan.display_cursor( fk7j3tnpandph ,null, ALLSTATS ));
显示上一个执行的SQL的执行计划:
select * from table(dbms_xplan.display_cursor(null,null, ALLSTATS ));
select * from table(dbms_xplan.display_cursor(null,null, ALLSTATS LAST ));
—-select sql_id from dba_hist_sqlstat where plan_hash_value !=0 and rownum<10;
如果通过AWR已经获取了SQL_ID,则可以直接得到执行计划:
select * from table(dbms_xplan.display_awr( sql_id ));
select * from table(dbms_xplan.display_cursor( sql_id ,null, ADVANCED ALLSTATS LAST PEEKED_BINDS ));
查看SQL的历史执行计划:
select * from table(dbms_xplan.display_awr( 6pkd06hdx99xk ));
select * from table(dbms_xplan.display_cursor( 6pkd06hdx99xk ,null, ADVANCED ALLSTATS LAST PEEKED_BINDS ));
获取SQL的一个绑定变量:
SELECT VALUE_STRING FROM v$sql_bind_capture WHERE sql_id = 6pkd06hdx99xk ;
SELECT snap_id,NAME,position,value_string,last_captured,WAS_CAPTURED FROM dba_hist_sqlbind WHERE sql_id = c1j018vt5ajdu ;
select sql_id,sql_plan_line_id,sql_plan_hash_value,count(*)
from v$active_session_history
where sql_id= &sqlid
group by sql_id,sql_plan_line_id,sql_plan_hash_value;
历史的会话信息:
select sql_id,sql_plan_line_id,sql_plan_hash_value,count(*)
from dba_hist_active_sess_history
where sql_id= &sqlid
group by sql_id,sql_plan_line_id,sql_plan_hash_value;
select a.sql_id,a.sql_plan_line_id,a.sql_plan_hash_value,count(*)
from dba_hist_active_sess_history a,dba_hist_sqlstat b
where a.instance_number=b.instance_number and a.snap_id=b.snap_id
and a.dbid=b.dbid and a.sql_id=b.sql_id and a.sql_id= &sqlid
group by a.sql_id,a.sql_plan_line_id,a.sql_plan_hash_value;
查看等待事情的情况:
select event,count(distinct session_id),count(*) from v$active_session_history where sql_id= 92b382ka0qgdt group by event;
如果知道SQL_ID,则通过下面的方法获取执行计划:
select * from table(dbms_xplan.display_cursor( &sql_id ,null, PEEKED_BINDS ));
v$active_session_history
dba_hist_active_sess_history
找到执行计划哪一步是瓶颈:
select count(*),sql_plan_line_id,sql_plan_hash_value,sql_id
from gv$active_session_history
where sql_id= 92b382ka0qgdt
group by sql_plan_line_id,sql_plan_hash_value,sql_id
order by 2;
找到执行计划哪一步是瓶颈,简单版:
select count(*),sql_plan_line_id
from gv$active_session_history
where sql_id= 92b382ka0qgdt
group by sql_plan_line_id
order by 2;
找到执行计划哪一步是瓶颈,简单版:
select count(*),sql_plan_line_id,sql_plan_hash_value
from gv$active_session_history
where sql_id= 92b382ka0qgdt
group by sql_plan_line_id,sql_plan_hash_value
order by 2;
1、定位SQL
2、显示执行计划
3、定位 plan_line_id
4、针对性优化
1、定位SQL
2、显示执行计划
3、寻找历史执行计划
4、绑定历史执行计划
如果索引有问题的话,就查询索引的情况:
col index_name for a40
col collist for a80
select index_name,listagg(column_name, , ) within group(order by column_position) as collist
from dba_ind_columns
where table_name = &tname
group by index_name
/
HIT:
/*+ NO_MERGE */ —-no_merge表明视图不合并,merge表明视图合并
/*+ leading(TMP) */
/*+ CARDINALITY(B,34343434343) */
/*+ gather_plan_statistics */
dbms_monitor.report_sql_monitor
display_cursor(format=> IOSTATS )
下面3个视图的结构基本一致:
v$sql
v$sqlstats
dba_hist_sqlstat 这个表中都是delta数据:elapsed_time_delta,BUFFER_GETS_DELTA,EXECUTIONS_DELTA,ROWS_PROCESSED_DELTA
sql_id
plan_hash_value
elapsed_time
elapsed_time_delta
BUFFER_GETS
BUFFER_GETS_DELTA
EXECUTIONS
EXECUTIONS_DELTA
ROWS_PROCESSED
ROWS_PROCESSED_DELTA
查看统计信息:
select sql_id,plan_hash_value,
sum(elapsed_time) els,
sum(elapsed_time)/greatest(sum(executions),1) els_per_exec,
sum(buffer_gets) gets,
sum(buffer_gets)/greatest(sum(executions),1) get_per_exec,
sum(executions) execs,
sum(rows_processed) rowcnt,
sum(elapsed_time)/greatest(sum(rows_processed),1) els_per_row,
sum(buffer_gets)/greatest(sum(rows_processed),1) get_per_row
from v$sqlstats
where
sql_id= &sqlid
group by sql_id,plan_hash_value
order by els_per_exec;
查看历史的统计信息
select sql_id,plan_hash_value,
sum(elapsed_time_delta) els,
sum(elapsed_time_delta)/greatest(sum(executions_delta),1) els_per_exec,
sum(buffer_gets_delta) gets,
sum(buffer_gets_delta)/greatest(sum(executions_delta),1) get_per_exec,
sum(executions_delta) execs,
sum(rows_processed_delta) rowcnt,
sum(elapsed_time_delta)/greatest(sum(rows_processed_delta),1) els_per_row,
sum(buffer_gets_delta)/greatest(sum(rows_processed_delta),1) get_per_row
from dba_hist_sqlstat
where
sql_id= &sqlid
group by sql_id,plan_hash_value
order by els_per_exec;
绑定执行计划:
dbms_sqltune.import_sql_profile
coe_profile.sql
查询表的数据的分布情况:
select column_name,t.num_rows,c.NUM_NULLS,c.num_distinct
from dba_tables t,dba_tab_columns c
where t.owner=c.owner and t.table_name=c.table_name and t.table_name= &tablename
order by num_distinct;
查看表的每个列的数据分布情况:
select column_name,t.num_rows,c.NUM_NULLS,c.num_distinct
from dba_tables t,dba_tab_columns c
where t.owner=c.owner and t.table_name=c.table_name and t.table_name= FBP_BOE_TYPE
order by num_distinct;
—-查询执行时间最长的SQL
select *
from (select sa.SQL_TEXT,
sa.SQL_FULLTEXT,
sa.EXECUTIONS “执行次数”,
round(sa.ELAPSED_TIME / 1000000, 2) “总执行时间”,
round(sa.ELAPSED_TIME / 1000000 / sa.EXECUTIONS, 2) “平均执行时间”,
sa.COMMAND_TYPE,
sa.PARSING_USER_ID “用户ID”,
u.username “用户名”,
sa.HASH_VALUE
from v$sqlarea sa
left join all_users u
on sa.PARSING_USER_ID = u.user_id
where sa.EXECUTIONS > 0
order by (sa.ELAPSED_TIME / sa.EXECUTIONS) desc)
where rownum <= 50;
select sid,serial#,username,schemaname,osuser,machine,terminal,program,owner,object_name,object_type,o.OBJECT_id
from dba_objects o,v$locked_object i,v$session s
where o.object_id=i.object_id and s.sid=i.session_id;
做SQL优化必定要把范围控制在最小范围内,控制在当前SQL内最好。
快速优化SQL的方法:
1、找到合适的历史的执行计划,进行绑定。
2、找到执行计划的瓶颈,针对性优化。
3、使用合适的索引、连接顺序、连接方法。
性能问题的定位:原则就是尽可能小范围分析问题
1、SQL层
如果能定位SQL就不要从会话层面分析
2、会话层
如果能从会话层定位就不要从系统层分析
V$SESSION,V$SESSTAT,V$SESSION_WAIT,V$SQL,V$LOCK,SQL_TRACE
3、系统层
如果无法定位任何性能问题,从系统层面入手
AWR,TOP ,IOSTAT
分析一个孤立的AWR是没有意义的。要结合业务分析,并且要对比正常时候的AWR来分析。
数据库负载重并不必定有问题。
高效的SQL来自于对业务的理解和对SQL执行过程的理解。
CBO能够做的事情超级少。
AWR信息的来源表:
select table_name from dict where table_name like %DBA_HIST_% ;
AWR中DB_TIME:所有用户操作数据库的时间总和。列如有10个用户每个用户操作1分钟,那么DB TIME 就是10分钟。
CURS/SESS :每个会话发出的SQL情况。
绑定变量在OLTP中使用,在OLAP中没有必要使用。
OLTP关注的是内存,OLAP关注的是I/O。
我们要关注的是前台的等待事件:Foreground events
DB FILE SEQUENTIAL READ 的值比较大,说明有大量的根据索引的查询。
ASH报告间隔时间可以准确到分钟,因而ASH可以提供比AWR更详细的关于历史会话的信息,可以作为AWR的补充。
v$active_session_history —-当前会话的采样数据,1S钟更新一下快照
dba_hist_active_sess_history —-保留v$active_session_history再早的数据
如果是要会话层面很详细的数据就要做ASH,如果你要整体的性能数据就要做AWR.
RAC的优化设计:业务分割
优点:避免数据在实例内存间传递导致的性能下降。
缺点:数据无法使用全部节点资源。
RAC正面:多个实例处理数据,充分利用系统资源
RAC负面:大量的数据需要在实例的内存间传递,影响性能
如果Interconnect导致严重的性能下降,就思考把并行开在一个实例上。
如果充分利用资源,能够提高性能,那么就把并行开在不同的实例上。
select name,value v$sysstat where name like %global cache% ;
性能优化是一个和业务密切相关的过程,单纯的数据库层面优化没有前途。
只能从架构上解决海量数据的存储问题。
HASH分区就是单纯的把数据均匀的分布在各个分区,基本与业务无关,这种分区用的比较少。
主要是范围分区和列表分区。
对于分区表尽量不要建立全局索引。做DDL操作就会使全局索引无效。要建立本地分区索引LOCAL INDEX。一个分区对应一个索引。
做更新时就不会使本地分区索引无效。
全局索引和分区索引的性能基本是一样的。
分区索引的目的在于数据的管理而非性能。
一个分区表上如果常常有DDL操作,将会导致全局索引失效,需要对索引重建,此时创建分区索引更加适合。
ORACLE发明分区表只是解决数据管理上的思考,而在性能上只是附加的思考。
exec dbms_stats.gather_table_stats(user, t ,method_opt => for all columns size 254 ); —-收集统计信息,并加上直方图的信息
method_opt:主要是用来做直方图的
size 254:说明建立254个桶,最多只能建立254个桶
for all columns:说明对所有的列进行直方图统计
for all hidden columns: 统计你看不到列的直方图
for all indexed columns: 统计所有索引列的统计信息
exec dbms_stats.gather_table_stats(user, t ,method_opt=> for all columns size 1 ); —-对表t收集统计信息但不创建直方图
size 1:表明不创建直方图
user_tab_modifications 跟踪表的修改。
当表的数据修改超过10%,ORACLE会重新分析。
定时任务 GATHER_STATS_JOB 负责重新收集过旧的统计信息。
查看系统默认的任务的执行情况:
select log_id,job_name,status,to_char(log_date, DD-MON-YYYY HH24:MI ) log_date
from dba_scheduler_job_run_details where job_name= GATHER_STATS_JOB ;
查看表的修改情况:
exec DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;
select inserts,updates,deletes,timestamp from user_tab_modifications where table_name= T ;
exec dbms_stats.gather_table_stats(user, t ,CASCADE=>true); —-将表和索引一起分析
exec dbms_stats.delete_table_stats(user, t ,CASCADE_parts=>false); —–删除表的统计信息
开启增量统计信息:
exec dbms_stats.set_table_prefs( scott , cmp , INCREMENTAL , TRUE );
收集一次统计信息:
exec dbms_stats.gather_table_stats(ownname=> scott ,tabname=> cmp );
直方图:ORACLE对列上的数据的分布进行统计分析,对数据倾斜分布时很有用。
数据分布不均匀就表明数据倾斜。
直方图的类型:频率直方图,高度平衡直方图。
动态采样:
LEVEL 10:对所有数据进行采样分析
LEVEL 1-10:采样的数据量逐级递增
创建扩展统计信息:
exec dbms_stats.gather_table_stats(OWNNAME => DAVE ,TABNAME => DAVE ,method_opt => for columns(object_name,object_type) );
exec dbms_stats.gather_table_stats(OWNNAME => DAVE ,TABNAME => DAVE ,method_opt => for columns(UPPER(STATUS)) );
在海量数据的表中执行DELETE将是一个灾难。
在OLAP中执行计划多变。在OLTP中执行计划基本不变。
soft-sfot-parse —–游标通道没有关闭,直接使用游标通道,不需要重新打开游标
游标指向一个SQL.
一条SQL第一次运行就是父游标,第二次运行就是子游标。
select sql_id,child_number,loads from v$sql where sql_text= select * from emp where 1=0 ;
SQL的文本一样那么父游标就一样。
查询执行计划最慢的步骤:
select count(*),sql_plan_line_id
from gv$active_session_history
where sql_id= 2vcdzpaknk46s
group by sql_plan_line_id
order by 2;


