数据库性能问题诊断与分析

1.SQL_TRACE及10046事件的基础介绍

SQL_TRACE/10046事件是oracle提供的用于进行SQL跟踪的手段,是强有力的辅助诊断工具。当在数据库中启用SQL_TRACE或者设置10046事件后,Oracle将会启动内核跟踪程序,持续记录会话的相关信息,并写入到相应的trace文件中。跟踪记录的内容包括SQL的解析过程、SQL的执行计划、绑定变量的使用以及会话中发生的等待事件等。

1.1在全局启用SQL_TRACE

可以通过sql命令启动SQL_TRACE,或者在初始化参数里面。

SQL> alter database set sql_trace=true;

在全局启用SQL_TRACE会导致所有的进程的活动被跟踪,包括后台进程和所有用户进程,这通常会导致比较严重的性能问题,所以在生产环节中要谨慎使用。

1.2在当前session级设置

SQL>alter session set sql_trace=true;

大多数时候使用SQL_TRACE来跟踪当前进程。通过跟踪当前进程可以发现当前操作的后台数据库的递归活动,研究SQL执行及发现后台错误等。
此时的SQL操作将被跟踪:

SQL> select count(*)  from dba_users;
  COUNT(*)
----------
        49

结束跟踪:

SQL>alter session set sql_trace=false;

在session级别设置,只对当前session进行跟踪,在实例级别,会对实例上所有的SQL做跟踪,这种方式跟踪的SQL太多,代价是非常大的,所有很少用。如果是在初始化文件里面设置,只需要在参数文件里添加一个sql_trace 参数即可。

1.3跟踪其他用户进程

在很多时候需要跟踪其他用户的进程,而不是当前用户,可以通过Oracle提供的系统包DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION来完成。

1)trace文件的路径

启用sql_trace前我们首先要确定跟踪文件的存放位置,即user_dump_dest下

SQL> show parameter user_dump_dest;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
user_dump_dest                 string      f:\app\administrator\diag\rdbms\orcl\orcl\trace

其中user_dump_dest,instance_name的值可以通过show命令得到,backgroudProcessID的值就需要首先获取session的sid然后根据sid的值查询v$session中进程的地址,然后根据进程地址找到processID,在11G以前可以通过下面这个语句获取当前session的sql_trace文件的路径

SQL> select
a.value || '/' || b.instance_name || '_ora_' || c.spid || '.trc' trace_file
from
(select value from v$parameter where name= 'user_dump_dest') a,
(select instance_name from v$instance) b,
(select spid from v$process where addr=(select paddr from v$session where sid=(select distinct sid from v$mystat))) c;
TRACE_FILE
--------------------------------------------------------------------------------
f:\app\administrator\diag\rdbms\orcl\orcl\trace/orcl_ora_10680.trc

在11g以后v$process视图里面tracefile 字段直接给出了这个值,因此不需要写上面那么麻烦的语句

SQL> select tracefile from v$process where addr=(select paddr from v$session where sid=(select distinct sid from v$mystat));

另外也可以手工更改产生trace文件的名称例如

SQL> alter session set tracefile_identifier='测试组'

2) 通过查询v$session可以获得SID/SERIAL等信息,获得进程信息后,选择需要跟踪的进程,设置跟踪。

SQL> select sid,serial# ,username from v$session where username is not  null;

设置跟踪:

SQL> exec dbms_system.set_sql_trace_in_session(63,52173,true);

停止跟踪:

SQL> exec dbms_system.set_sql_trace_in_session(63,52173,false);

3)查看trace文件信息

如果你想确切地知道sql语句的每一步执行时如何操作的,就需要分析原始的trace文件,下面给出了这条sql语句的关键部分

Trace file f:\app\administrator\diag\rdbms\orcl\orcl\trace\orcl_ora_11584.trc
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Windows NT Version V6.1 Service Pack 1 
CPU                 : 4 - type 8664, 2 Physical Cores
Process Affinity    : 0x0x0000000000000000
Memory (Avail/Total): Ph:2714M/8092M, Ph+PgF:9477M/16182M 
Instance name: orcl
Redo thread mounted by this instance: 1
Oracle process number: 29
Windows thread id: 11584, image: ORACLE.EXE (SHAD)


*** 2017-06-20 14:41:50.548
*** SESSION ID:(63.52173) 2017-06-20 14:41:50.548
*** CLIENT ID:() 2017-06-20 14:41:50.548
*** SERVICE NAME:(orcl) 2017-06-20 14:41:50.548
*** MODULE NAME:(w3wp.exe) 2017-06-20 14:41:50.548
*** ACTION NAME:() 2017-06-20 14:41:50.548
 
CLOSE #2:c=0,e=27,dep=0,type=1,tim=368624802714
=====================
PARSING IN CURSOR #3 len=154 dep=0 uid=102 oct=3 lid=102 tim=368624807375 hv=2174186802 ad='7ffbee326f0' sqlid='1x22q820tfx9k'
select * from SYS_ROLE  where exists (select ROLE_ID from sys_user_role where sys_user_role.ROLE_ID=SYS_ROLE.ROLE_ID and sys_user_role.user_id=:"SYS_B_0")
END OF STMT
PARSE #3:c=0,e=1135,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=0,tim=368624807374
EXEC #3:c=0,e=1984,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3232332846,tim=368624809497
FETCH #3:c=0,e=164,p=0,cr=9,cu=0,mis=0,r=1,dep=0,og=1,plh=3232332846,tim=368624810883
STAT #3 id=1 cnt=1 pid=0 pos=1 obj=0 op='NESTED LOOPS  (cr=9 pr=0 pw=0 time=0 us)'
STAT #3 id=2 cnt=1 pid=1 pos=1 obj=0 op='NESTED LOOPS  (cr=8 pr=0 pw=0 time=0 us cost=5 size=101 card=1)'
STAT #3 id=3 cnt=1 pid=2 pos=1 obj=0 op='SORT UNIQUE (cr=7 pr=0 pw=0 time=0 us cost=3 size=29 card=1)'
STAT #3 id=4 cnt=1 pid=3 pos=1 obj=92656 op='TABLE ACCESS FULL SYS_USER_ROLE (cr=7 pr=0 pw=0 time=0 us cost=3 size=29 card=1)'
STAT #3 id=5 cnt=1 pid=2 pos=2 obj=92648 op='INDEX UNIQUE SCAN PK_SYS_ROLE (cr=1 pr=0 pw=0 time=0 us cost=0 size=0 card=1)'
STAT #3 id=6 cnt=1 pid=1 pos=2 obj=92647 op='TABLE ACCESS BY INDEX ROWID SYS_ROLE (cr=1 pr=0 pw=0 time=0 us cost=1 size=72 card=1)'
CLOSE #3:c=0,e=18,dep=0,type=0,tim=368624812253

我们看到Oracle首先对这条sql语句做分析,并且有一个游标号CURSOR #3,这个在整个trace文件中不是唯一的,当一条sql语句执行完毕后,这个号会被另外一个sql语句重用
我们还可以看到这条sql语句被分析了一次,执行了一次,fetch了1次,stat#3是对这条sql语句执行过程中的资源消耗的统计,这些输出顺序就是sql语句的执行顺序,通过这些顺序就可以了解到sql语句是如何一步一步执行的。
下面是列出了这些指标的解释

==PARSING IN CURSOR 部分==

  • len:被分析sql的长度
  • dep:产生递归sql的深度
  • uid:user id
  • otc:Oracle command type命令的类型
  • lid:私有用的id
  • tim:时间戳
  • hv: hash value
  • ad: sql address

==PARSE,EXEC,FETCH部分==

  • c: 消耗的cpu time
  • e:elapsed time 操作的用时
  • p:physical reads次数
  • cr:consistent reads数据的块
  • cu:current方式读取的数据块
  • mis:cursor miss in canche硬分析次数
  • r:rows处理的行数
  • dep:depth递归sql的深度
  • og:optimize goal优化器模式
  • tim:timstamp时间戳

==stats部分==

  • id:执行计划的行源号
  • cnt:当前行源返回的行数
  • pid:当前行源的父号
  • pos:执行计划中的位置
  • obj:当前操作的对象id
  • op:当前行源的数据访问操作

2.10046事件说明

10046事件是Oracle提供的内部事件,是对SQL_TRACE的增强 。
10046事件可以设置一下4个级别:

  • 1)Level 1:启用标准的SQL_TRACE功能,等同于sql_trace的功能。
  • 2)Level 4 在Level 1的基础上收集绑定变量的信息
  • 3)level 8 在Level 1的基础上增加了等待事件的信息
  • 4)level12 等同于Level 4 + Level *,集同时收集绑定变量和等待事件信息

可以看出level级别越高,收集的信息越全面,我们用下面例子来分别看下这几个级别的作用

2.1 LEVEL 4

--首先查询trace文件路径

SQL> select tracefile from v$process where addr=(select paddr from v$session where sid=(select distinct sid from v$mystat));
SQL> create table test as select * from dba_objects;
SQL> exec dbms_stats.gather_table_stats('sys','test');

--设定10046事件的级别为4

SQL> alter session set events '10046 trace name context forever,level 4';

--定义2个变量x,y

SQL> var x number;
SQL> var y varchar2(10);
SQL> exec :x := 20;
SQL> exec :y :='TEST';

--通过绑定变量查询表

SQL> select object_id,object_name from test where object_id=:x or object_name=:y;

这样就完成了使用10046事件做SQL trace的工作,注意,LEVEL 4获取的绑定变量的信息只能在原始的trace文件里面获取,在通过tkprof工具格式化后是看不到的,下面是这条sql在原始文件中的关键部分。

2.2 LEVEL8

--打开另外一个session 2 模拟TX - row lock contention等待事件

SQL> update test set object_id=10 where object_name='TEST';

--更新同一行,这个时候session就被另外一个session阻塞了

SQL> update test set object_id=20 where object_name='TEST';

--等待1分钟后,在session 2 commit

SQL> commit;

--回到session 通过绑定变量做查询

SQL> var x number;
SQL> var y varchar2(10);
SQL> exec :x := 20;
SQL> exec :y :='TEST';
SQL> col object_name for a10;
SQL> select object_id,object_name from test where object_id=:x or object_name=:y;
SQL> alter session set events '10046 trace name context off';

3.ORACLE TKPROF使用

Tkprof是一个用于分析Oracle跟踪文件并且产生一个更加清晰合理的输出结果的可执行工具。如果一个系统的执行效率比较低,一个比较好的方法是通过跟踪用户的会话并且使用Tkprof工具使用排序功能格式化输出,从而找出有问题的SQL语句。

3.1 TKPROF 命令语法:

TKPROF filename1, filename2 [ SORT = [ opion][,option] ]
[ PRINT = integer ]
[ AGGREGATE = [ YES | NO ] ]
[ INSERT = filename3 ]
[ SYS = [ YES | NO ] ]
[ [ TABLE = schema.table ] | [ EXPLAIN = user/password ] ]
[ RECORD = filename ]

相关说明:

  • filename1 指定的输入文件,可以是多个文件联起来。
  • Filename2 格式化输出文件。
  • SORT 在输出到输出文件前,先进程排序。如果省去,则按照实际使用的顺序输出到文件中。
  • PRINT 只列出输出文件的第一个integer 的SQL语句。默认为所有的SQL语句。
  • AGGREGATE 如果= NO ,则不对多个相同的SQL进行汇总。
  • INSERT SQL 语句的一种,用于将跟踪文件的统计信息存储到数据库中。在TKPROF创建脚本后,在将结果输入到数据库中。
  • SYS 禁止或启用 将SYS用户所发布的SQL语句列表到输出文件中。
  • TABLE 在输出到输出文件前,用于存放临时表的用户名和表名。
  • EXPLAIN 对每条SQL 语句确定其执行规划。并将执行规划写到输出文件中。

3.2 对Tkprof命令输出的解释

SQL处理的不同的阶段


image
  • CALL:每次SQL语句的处理都分成三个部分
  • Parse:这步将SQL语句转换成执行计划,包括检查是否有正确的授权和所需要用到的表、列以及其他引用到的对象是否存在。
  • Execute:这步是真正的由oracle来执行语句。对于insert、update、delete操作,这步会修改数据,对于select操作,这步就只是确定选择的记录。
  • Fetch:返回查询语句中所获得的记录,这步只有select语句会被执行。
  • COUNT:这个语句被parse、execute、fetch的次数。
  • CPU:这个语句对于所有的parse、execute、fetch所消耗的cpu的时间,以秒为单位。
  • ELAPSED:这个语句所有消耗在parse、execute、fetch的总的时间。
  • DISK:从磁盘上的数据文件中物理读取的块的数量。一般来说更想知道的是正在从缓存中读取的数据而不是从磁盘上读取的数据。
  • QUERY:在一致性读模式下,所有parse、execute、fetch所获得的buffer的数量。一致性模式的buffer是用于给一个长时间运行的事务提供一个一致性读的快照,缓存实际上在头部存储了状态。
  • CURRENT:在current模式下所获得的buffer的数量。一般在current模式下执行insert、update、delete操作都会获取buffer。在current模式下如果在高速缓存区发现有新的缓存足够给当前的事务使用,则这些buffer都会被读入了缓存区中。
  • ROWS: 所有SQL语句返回的记录数目,但是不包括子查询中返回的记录数目。对于select语句,返回记录是在fetch这步,对于insert、update、delete操作,返回记录则是在execute这步。

3.3 使用Tkprof命令分析trace文件

image

经验总结

  • Query + Current = Logical Reads (total number of buffers accessed)
  • query+current/rows 平均每行所需的block数,太大的话(超过20)SQL语句效率太低
  • Parse count/Execute count parse count应尽量接近1,如果太高的话,SQL会进行不必要的reparse
  • rows Fetch/Fetch Fetch Array的大小,太小的话就没有充分利用批量Fetch的功能,增加了数据在客户端和服务器之间的往返次数。
  • disk/query+current 磁盘IO所占逻辑IO的比例,太大的话有可能是db_buffer_size过小(也跟SQL的具体特性有关)
  • elapsed/cpu 太大表示执行过程中花费了大量的时间等待某种资源
  • cpu Or elapsed 太大表示执行时间过长,或消耗了了大量的CPU时间,应该考虑优化
  • 执行计划中的Rows 表示在该处理阶段所访问的行数,要尽量减少
  • DISK是从磁盘上的数据文件中物理读取的块的数量。一般来说更想知道的是正在从缓存中读取的数据而不是从磁盘上读取的数据。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 背景: 阅读新闻 12C CDB模式下RMAN备份与恢复 [日期:2016-11-29] 来源:Linux社区 作...
    阳屯okyepd阅读 3,332评论 0 7
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • 穿越十月的歌声 ■曾晓琴 十月金风吹 谁 填满空虚与寂寞 树叶摇摆的时候 那歌 将流水推向远方 ...
    蜗牛向前行123阅读 340评论 1 10
  • 我喜欢晴天 因为晴天可以卖土豆 阴雨天则不行 但是 我也不讨厌阴雨天 因为下雨了 妈妈种的玉米 长势就好 2017...
    吻章阅读 162评论 0 0