第1章 OWI介绍
记录和观察进程所经历的等待现象的功能和界面以及方法论,统称为OWI,也就是Oracle Wait Interface.等待事件的P1、P2、P3值可以通过v$session_wait、v$session视图等动态视图 或者sql trace文件观察。各事件的P1、P2、P3的意义都不尽相同,可通过v$event_name视图进一步确认。Oracle世界里非常广泛地使用“资源”这个词,与我们一般理解的“资源”不同。OWI观点上的“资源”只限于事件的P1、P2、P3三个参数表达的范围,各等待事件的P1、P2、P3信息,可参考v$event_name视图或Oracle文档 Reference。
Oracle利用等待次数、超时次数、等待时间三个值表示等待现象,从用户角度看,感觉最为有用的是“等待 时间”,以等待次数判断争用是没有任何意义的,通过等待时间可最为准确地分析争用程度。
响应时间(Response Time)=工作时间(Service Time)+等待时间(Wait Time)。
使用OWI方式与使用其他性能诊断方式最大的不同,就是OWI是面向问题的。只有着眼于当前系统发生的等待现象,才可最直观地掌握性能问题。利用Oracle 10g开始提供的AWR性能历史记录管理功能以OWI为基础,可以对过去特定时刻的性能问题进行分析。
一直到Oracle 8i,buffer cache hit ratio(BCHR),被 视为诊断高速缓冲区性能最为重要的因素,但是Oracle 9i之后,就不能再利用BCHR诊断性能。BCHR在内存价格贵,I/O速度又很慢,而且cpu数量有限的时候是很有意义的指标。但是在千兆内存和已明显得到改善那的I/O设备,还有数十个CPU的服务器上 ,比起BCHR,减少锁存器争用更为重要。Oracle为了减少锁存器争用,不断改善告诉缓冲区的管理方法。Buffer Pinning、多重缓冲池、多种块大小等就是其具有代表性的方法。也因为如此,传统的计算方式中的BCHR,也基本上失去了意义。
OWI不是“推测”,而是基于“事实”和“数据”,将性能分析变为可能的方法论。OWI上的事实是以特定时间的等待次数、超时次数、等待时间来表示的。如果灵活 使用的OWI,则可以摆脱性能问题的模糊感,利用“观察的事实和数值”,可以将问题以简洁的数据表示。也就是通过OWI,我们可以将负责的性能问题,解释为任何人都易于理解的值、定量的值。如果保存了等待事件和性能指标的历史记录,就可以更为准确地进行分析。
通过OWI,Oracle的调优不再是艺术,而是定位于医学和科学领域。医生通过症状推断病因,利用经验和知识治疗病症。与此相同,DBA利用等待事件,推断发生性能问题原因,并通过各种等待事件相关知识和经验,可以解决性能问题,通过对等待事件的慎密分析和对Oracle内部结构的加深理解、经验或知识的积累过程,使用OWI的性能分析会更为精辟,并会不断发展。
从Oracle 10g开始,只要看到等待事件名,就可以直观地掌握正在发生何种问题,如此提供了细分化的等待事件。特别是Oracle 10g的重要功能AWR和OWI方法论结合,不仅是当前的性能问题,而且连过去时刻的故障分析、性能趋势分析也变为可能。
本书没有按照Oracle类进行分类,而是为了更直观的理解,使用了“Buffer Cache /Library Cache/Row Catch/IO/Transaction/Segment/Sql statement/Network"分类方法。
pdf文档中通过链接查看所有相关视图。
1.3 OWI工具
1.3.1.OWI动态视图:v$event_name,v$system_event,v$session_event,v$session_wait(state=waiting,event<>idle),v$session_wait_history(默认累计提供10个,一般不够),v$system_wait_class,v$session_wait_class,v$event_histogram.
1.3.2.其他重要动态视图:
v$session :会话信息
v$active_session_history :会话历史记录信息,AWR功能的一部分,存储在share pool的ASH buffers区域,Oracle 利用DMA功能,美妙更新ASH
v$process :进程信息
v$transaction :事务信息
v$latch,v$latch_parent,v$latch_children,v$latch_holder :锁存器信息
v$lock,v$locked_object,v$enqueue_lock :锁信息
v$sql :sql信息
v$librarycache,x$kgllk,v$kglpn :库高速缓冲区信息
v$rowcache,v$rowcache_parent : 行高速缓冲区信息
v$sgastat :SGA信息
v$segment_statistics :Segment Level统计信息
v$sess_time_model,v$sys_time_model :Time Model信息
v$bh,x$bh :高速缓冲区信息
SYS AS SYSDBA>select pool,name,bytes from v$sgastat where name=‘ASH buffers‘;
POOL NAME BYTES
------------ -------------------------------------------------- ----------
shared pool ASH buffers 2097152
SYS AS SYSDBA>select distinct statistic_name from v$segment_statistics;
STATISTIC_NAME
----------------------------------------------------------------
gc buffer busy
db block changes
space used
segment scans
gc cr blocks received
gc current blocks received
row lock waits
buffer busy waits
physical reads
physical reads direct
physical writes
space allocated
logical reads
physical writes direct
ITL waits
15 rows selected.
x$bh,v$bh视图在研究高速缓冲区的工作机制时极为有用。
1.3.3 Extended Sql Trace
可通过10046事件激活,分四个等级(1,4,8,12)
默认?
为诊断SQL性能而使用sql trace时,为获得准确的信息,必须使用level 12,如果想利用sql trace分析等待事件,除了利用tkprof工具格式化的结果外,多数情况下还需要查看原始追踪文件。
for example:
1)当前会话上执行工作时:
alter session set events ‘10046 trace name context forever,level 12‘;
alter session set events ‘10046 trace name context off‘;
2)利用dbms_system,对其他会话执行Trace时:
exec sys.dbms_system.set_bool_param_in_session(sid=>,serial=>,parname=‘TIMED_STATISTICS‘,bval=>true);
exec sys.dbms_system.set_int_param_in_session(sid=>,serial=>,parname=>‘MAX_DUMP_FILE_SIZE‘,intval=>214783647);
exec sys.dbms_system.set_ev(sid,serial#,10046,12,‘‘);
3)利用dbms_monitor程序包,以客户端地址或Service、Module、Action名为标准执行追踪,创建对 多个会话的trace文件,,利用trcsess工具合并,最终可以制作成一个追踪文件。
4)利用oradebug,对其他会话进行追踪
oradebug setospid 12345
oradebug unlimit
oradebug event 10046 trace name context forever,level 12
...
oradebug event 10046 trace name context off
oradebug tracefile_name 显示跟踪文件名
1.3.4 oradebug和dump
oradebug广为人知的方法有如下几种,转储文件和追踪在USER_DUMP_DEST参数指定的目录下
诊断事件的执行(可用10046,10053等等待事件)
执行转储 (可执行SGA、PGA、library cache、row cache、buffers、enqueue、latch、heap、hanganalyze等转储工作。这种转储文件,有助于理解Oracle内部结构。
sql>oradebug setmypid --绑定在当前会话上
sql>oradebug dump library_cache 10
sql>oradebug dump row_cache 10
sql>oradebug dump buffers 10
sql>oradebug dump latches 10
sql>oradebug dump headdump 2
sql>oradebug dump systemstate 10
sql>oradebug dump processstate 10
sql>oradebug tracefile_name
sql>oradebug unlimit
控制进程 :对特定进程可执行暂停、继续操作。
sql>oradebug setospid
sql>oradebug suspend
sql>oradebug resume
1.3.5 Automatic Workload Repository
AWR收集的数据如下:
Active Session History
负荷大的sql语句
系统级和会话级上的Time Model统计值
对于Segment和其他数据库对象的使用统计值
v$sesstat、v$sysstat、v$system_event、v$session_event等。
1.5 其他
本书使用的脚本
show_space
print_table
my_sess_event.sql:求当前会话的v$session_event视图的结果
sql>select event,total_waits ,time_waited from v$session_event
where sid=(select sid from v$mystat where rownum=1)
order by 3 desc;
show_param.sql: 显示包括隐含参数在内的参数值
sql> select ksppinm,ksppstvl
from x$ksppi x,x$ksppcv y
where(x.indx=y.indx)
and (translate(ksppinm,‘_‘,‘#‘) like ‘%&1%‘)
system_event.sql:v$system_event视图上,求整个系统的当前等待情况
sql> select *
from (
select event,total_waits,time_waited
from v$system_event
where wait_class<>‘Idle‘
order by 3 desc
)where rownum<=100;
sesstat.sql求当前会话的v$sesstat视图结果
sql> select n.name,sum(s.value)
from v$sesstat s,v$statname n
where n.name like ‘%&stat_name%‘ and s.statistic#=n.statistic# and s.sid=(select sid from v$mystat where rownum=1)
group by n.name
undosize.sql :获得当前事务的Undo数据信息
sql> select used_ublk,used_urec
from v$transaction t,v$session s
where s.sid=(select sid from v$mystat where rownum=1)
and s.taddr=t.addr
第2章 Latch 和 Lock
Oracle是一个巨大的同步机。Oracle利用锁存器(latch)和锁(lock)这两种同步机制来保护资源。
现在的Oracle环境具有的Mega-User、Mega-Resource两种特性,可能导致不愿意看到的锁争用发生。随着使用锁存器和锁管理的资源和用户数的剧增,大大增加了在获取锁存器和锁过程中发生争用的概率。
OWI提供何种锁存器和锁在什么情况下发生的“事实”,而对事实的说明则由分析人自己去做。若想解决锁存器和锁上发生的性能问题,不仅需要掌握锁存器和锁的工作方式,而且对具体资源等级上使用的锁存器和锁,也需要有比较详细的知识。
2.2 Latch
在Oracle concept上将latch归类为lightweight lock。但一般把latch和lock分为两个完全不同的对象。从物理角度上讲,锁存器是存在于share pool的一种内存结体。latch使用非常简单而小的内存区域,latch的get和release的操作与硬件匹配极度优化。
latch所保护的资源就是SGA。访问SGA的所有进程,在获得相应管辖的latch后,方可访问。获取latch失败的进程一直等待特定事件,知道获得latch为止。直到Oracle 9i一直用等待事件latch free。通过latch free事件的 p1=address、p2=latch#的值能获得锁存器名。10g开始对重要的latch使用更详细的等待事件名,剩下的latch仍使用latch free等待事件。
latch可进行如下分类:
父(parent)latch :下面有多个子锁存器的锁存器
独立(solitary)latch :整个实例上只有一个锁存器
子(child)lanth :属于父锁存器的锁存器
Oracle为了避免latch争用,不断改善内存结构和算法。因此,最好是通过v$latch_parent视图和v$latch_children视图,确认相应版本的特定latch对应情况,养成好习惯。
latch的工作机制:Oracle在latch获取过程中,为了从根本上防止死锁,赋予所有latch一个等级。子latch和其父latch拥有相同的等级。在拥有一个以上latch的状态下,还想获得其他latch的进程,就必须获得比最后一次获得的锁存器更高等级的latch。如果因某种原因,要获得比当前拥有的latch等级低或者等级相同的latch时,会以No-wait模式获取,以防止死锁引起的无限等待。latch基本上使用Exclusive模式。
Lath的获得:Willing-to-wait 以及 No-wait模式
1)Willing-to-wait模式下的Latch获得
欲获取latch的进程基本上使用Willing-to-wait模式。多个进程同时获取latch时的争用情况,用图表示如下:
************************************latch获得和自旋****************************************
最初的latch获得失败后不会马上睡眠,而是spin(自旋)(只有一个cpu的系统不执行自旋),因为如果陷入睡眠状态,在OS层面上会发生context switching,这部分资源消耗比起使用较少的cpu进行spin更多。因此,latch争用发生时,较高的cpu使用率不是实际工作过程中发生的,而是在为获取latch而spin过程中引发的。因此为了解决争用问题而增加cpu,只会进一步恶化问题。
即便尝试spin还是未能获得 latch的进程将进入到睡眠状态。解除睡眠状态的方法有两种:
一种是超时“苏醒”,超时时间(等待时间)通常由名为Exponential backoff sleep的算法决定。latch获得失败的进程,以厘秒(1/100)为单位按照1、1、2、2、4、4、8、8、16、16……顺序等待,最多增加到2秒,避免因为过度spin引起的cou使用过多。
一种是在latch等待列表(latch wait list)上登记自己,等待被其他进程“叫醒”。虽说使用了latch wait posting方法,但并不能保障latch获得顺序。
share pool latch和library cache latch等一些latch需要较长的时间获取,一般采用第2种方法。
2)No-wait模式下latch的获得
相关视图:v$latch、v$latch_parent、latch_children.
判断是否争用:Misses/Gets>1%(willing-to-wait) or Immediate_misses/(immediate_gets+immediate_misses)>1% (No-wait)
查询wait_time列
一般latch相关的等待事件:
latch:cache buffers chains、latch:cache buffers lru chain、latch:share pool、latch:library cache、latch:redo copy.
2.3 锁
Oracle的锁的分类有助于理解,但在理解实际工作机制上反而会出现混淆。作者综合Oracle的分类以及Steve Adams的分类,使用如下的分类方式:
Enqueue锁:就是以Enqueue结构管理的锁.(44页有具体的Enqueue结构)。Enqueue lock使用的资源是
User type lock:TX,TM,UL
system type lock:CF,US,CI,TC,JS,...
v$lock:type、ID1、ID2
v$session_wait:P1、P2、P3 (P1=name|mode、P2=ID1、P3=ID2)
select chr(bitand(p1,-16777216)/16777215)||chr(bitand(p1,16711680)/65535) "name",bitand(p1,65535) "Mode" from dual;
普通锁:有些锁虽然与Enqueue锁拥有相同的目的,但是以其他方式体现。了解普通锁发生争用与否的最佳方法是观察v$session_wait视图中是否发生等待现象。
row cache lock
library cache lock,library cache pin
buffer lock
观察以下等待事件:row cache lock,buffer busy waits,read by other session,library cache lock,library cache pin,DFS lock handle
如果说latch保护SGA,那么lock就是保护整个database。Enqueue锁所保护的资源被形式的资源标识符所标识。lock的名称和资源名称是相同的。构成资源标识符的ID1和ID2的值因资源类型而异,各资源使用唯一的可标识的值。
锁的工作机制:
锁的模式:
0 None
1 Null(N)
2 Sub-Shared(SS)或Row-Shared(RS)
3 Sub-exclusive(SX) 或 Row-Exclusive(RX)
4 Shared(S)
5 Shared-Sub-Exclusive(SSX) 或Shared-Row-Exclusive(SRX)
6 Exclusive(X)
锁模式的共享性
N SS SX S SSX X
N O O 0 O O O
SS O O 0 O O X
SX O O 0 X X X
S O O X O X X
SSX O O X X X X
X O X X X X X
Enqueue锁获取失败的进程,将自身登记到Enqueue资源的等待列表上。等待锁被释放并被叫醒。等待进程超时会自动苏醒(因锁类型不同,超时时间不尽相同),确认是否发生deadlock后重新回到等待状态。
相关的动态视图:v$lock,v$locked_object,dba_waiters
metalink doc id:122793.1 download........
N SS SX S SSX X
N O O 0 O O O
SS O O 0 O O X
SX O O 0 X X X
S O O X O X X
SSX O O X X X X
X O X X X X X
关于一些转储,分析dump文件略,可自行测试。
第3章 Oracle内部结构和OWI
3.1 buffer cache(高速缓冲区) 和OWI
3.1.1 buffer cache结构
sql>show aga
Oracle 为了有效管理buffer cache,使用Hash Chain结构。Hash Chain位于共享池内,使用Oracle典型内存结构的管理方法Bucket->chain->Header结构。
------------------54页见图。-----------------------------------
--------------------------------------------------------------
具有相同hash值的buffer header在hash bucket上以链表(chain)的形式相连。buffer header拥有对于缓冲区的Meta信息,并拥有缓冲区区域实际缓冲区的指针值。注意:hash chain位于share pool内,而实际缓冲区信息则位于buffer cache.
Hash Chain结构利用cache buffers chains latch保护。基本上每次只有一个进程获得仅有的一个cache buffers chain latch,一个cache buffers chains latch则管理多个Hash Chain。Oracle 9i开始,将cache buffers chains latch以shared 模式获得,但只限于只读操作。因此同时执行只读操作的进程之间能共享cache buffers chains latch.由于对缓冲区获得和释放buffer lock时,需要把cache buffers chains latch以Exclusive模式获得,所以即使在执行只读操作时,也会发生cache buffers chains latch 争用。
sql>select count(*) from v$latch_children where name=‘cache buffers chains‘; --cache buffers chains latch的数量
3.1.2 Working Set
Oracle为了有效使用buffer cache,使用两种LRU(least recently used)列。为提高List Scan的效率,将LRU和LRUW重新分为main list(主列) 和 auxiliary list (辅列).
LRU列
--主列 :已使用的缓冲区列,以hot和cold区域区分管理。(keep缓冲池和Recycle缓冲池与默认缓冲池不同,因为不需要区域之分,所以不拥有Hot区域)
--辅列 :空闲缓冲区列,更准确的表示则是未使用的的缓冲区或通过DBWR写入的缓冲区列。
LRUW列
--主列 :已修改的缓冲区列
--辅列 :当前通过DBWR写入中的缓冲区列
LRU和LRUW列总是成对(pair)出现,这一队列被称为工作组(working set),即working set=LRU+LRUW。ORACLE使用多个工作组,而一个cache buffers lru chain latch 管理一个工作组。
sql>select count(*) from v$latch_children where name=‘cache buffers lru chain‘;
Oracle有多种缓冲池(buffer pool),每个缓冲池各自使用独立的cache buffers lru chain latch。
sql>
--x$kcbwds=working Set, x$kcbwbpd=Buffer pool, v$latch_children=latch
select d.blk_size,c.child#,p,bp_name,c.gets,c.sleeps
from v$kcbwds d, v$latch_children c, x$kcbwbpd p
where d.set_latch=c.addr
and d.set_id between p.bp_lo_sid and p.bp_hi_sid
order by c.child#;
Server process扫描的所有的buffer cache登记到LRU列,所以有效管理LRU列十分重要。Oracle 8i之后的版本开始,为有效管理LRU列,使用以touch count基础的LRU算法,此算法用于管理LRU列的主列。具体工作方式略。
------------59 图---------------------------------------------------
----------------------------------------------------------------
图说明:LRU列的主列可分为Hot区域和Cold区域。检索空闲缓冲区时,首先在LRU列的辅助列上检索未使用的缓冲区。Single Block I/O读取的块插入到Mid-point.Multi-Block I/O读取的块插入到cold区域的尾部。如full table scan or Index Full Scan。
3.1.3 Buffer Lock
如果说,cache buffers chains latch和catch buffers lru chain latch起到保护Hash Chain结构和工作组(LRU+LRUW)结构的作用,buffer lock则起到保护缓冲区自身的作用。
3.1.4检索缓冲区的步骤和方法
start: 对于用户请求的块DBA和类利用hash函数创建hash值,检索Hash值对应的Hash bucket
--> 获得保护Hash Bucket的cache buffers chains latch,检索Hash Bucket上的chain后,确认块相应buffer Header存在与否,若存在,获取buffer lock(buffer busy waits or write complete waits).执行一系列工作,这就是logic reads。
--> 若buffer cache不存在块,将先获得管理工作组的cache buffers lru chain latch,检索空闲缓冲区,找到空闲缓冲区后,以exclusive模式获得buffer lock(read by other session),从数据文件将块读取到相应的缓冲区,从数据文件物理地读取块的一连串工作成为physical reads。若LRU列没有找到空闲缓冲区,服务器进程请求DBWR将脏缓冲区记录到数据文件里,以确保空闲缓冲区(free buffer waits)。
3.1.5 buffer cache dump 略
sql>alter session set event ‘immediate trace name buffers level 1‘; 或者
sql>oradebug dump buffers 1
利用X$BH视图也能得到有关Buffer Header的详细信息。联合v$latch_children 和 v$tablespace ...
3.2 shared pool/Library Cache 和OWI
3.2.1 shared pool 和堆
sql>show sga
sql>select count(*) from v$sgastat where pool =‘shared pool‘; --总共分为多少个内存区域
sql>select *
from (
select name ,bytes from v$sgastat where pool =‘shared pool‘
order by bytes desc
) where rownum<=20;
shared pool的结构大体上如下分类
*Permanent Area:peocess,session,segment array(enqueue,transaction...)等。进程列表、会话列表、Enqueue列表、事务列表等待资源分配到共享池的永久区域(Permanent Area),与实例的寿命相同。
*Library Cache:管理执行SQL语句必要的全部对象(SQL、表、视图、Procedure等)信息
*Row Cache:也称为Dictionary Cache,管理Oracle所使用的字典(dictionary)信息。
*Reserved Area:保留区域。为动态分配内存,Oracle将分配部分保留区域。
共享池利用堆这种内存管理方式进行管理。利用Heap Manager(KGH,kernel Ceneric Heap)进行管理,是Oracle最基本的内存分配方法。从物理观点上讲,shared pool内存是将Granule追加堆积的方式分配,所以使用“堆(heap)”这个词。
-----------------------图 69 ------------------------------------
---------------------------------------------------------------------
sql>alter session set events ‘immediate trace name headdump level 2‘;
具体分析略
发生Hard Parsing时,进程从shared pool分配新sql语句所需的从存储空间你,必须获得shared pool latch. shared pool latch 基本上全实例只有一个,且必须在分配内存(chunk)的过程中一直拥有。
Oracle 9i以上版本开始,shared pool可分为多个副池管理。副池拥有独立的空闲列、LRU列、shared pool latch。因此共享池较大时分为多个副池管理,能减少shared pool latch争用。
3.2.2 库高速缓冲区(library cache)结构
共享池中最关键的部分是高速缓冲区,它是管理与sql语句的执行相关的所有信息的区域。库高速缓存是Hash Table→Bucket→Chain→Handle→Objec的就结构。 一个Library Cache Handle管理一个Library Cache Object(LCO),handle对实际LCO起到Meta信息和指针作用,LCO保存着实际信息。LCO具体的信息描述见书,注意sql语句如何保障唯一(通过创建父LCO,子LCO)。
------------------------------图 72--------------------------------------------------
-------------------------------------------------------------------------------------
sql> alter session set events ‘immediate trace name library_cache level 10‘;
具体分析...
欲检索库告诉缓冲区的所有进程,必须获得保护相应Hash Bucket的library cache latch.
--------------------------------------------------------------------------------------------
关于library cache lock 以及library cache pin的分析 by eagle
Oracle使用两种数据结构来进行shared pool的并发控制:lock 和 pin.
Lock比pin具有更高的级别.lock将会在pin之前获得,并被加载到library cache handle上
Lock在handle上获得,在pin一个对象之前,必须首先获得该handle的锁定.
锁定主要有三种模式: Null,share,Exclusive.
在读取访问对象时,通常需要获取Null(空)模式以及share(共享)模式的锁定.
在修改对象时,需要获得Exclusive(排他)锁定.
在锁定了Library Cache对象以后,一个进程在访问之前必须pin该对象.
同样pin有三种模式,Null,shared和exclusive.
只读模式时获得共享pin,修改模式获得排他pin.
通常我们访问、执行过程、Package时获得的都是共享pin,如果排他pin被持有,那么数据库此时就要产生等待.
---------------------------------------------------------------------------------------------
3.2.3 SQL的执行
1)用户请求执行sql,Oracle获得Hash bucket的library cache latch,然后确认library cache上是否存在相同的sql,即相同的LCO。若存在,跳至第4步执行(soft parsing).
2) 若不存在相同sql,在获得shared pool latch后,从空闲列上查找最适合大小的chunk. 若不存在最适合大小的chunk,则查找更大的空闲chunk后split。若检索了所有空闲列后没有找到恰当的空闲chunk,则检索LRU列。若在LRU列上检索也不能确保适当大小的chunk,则追加分配共享池的剩余内存空间。以上过程都失败,发生错误ora-04031
3) 若找到适当的chunk,对sql相应的handel(library cache handel)以exclusive模式获得,并创建LCO信息。创建LCO信息后,library cache lock变换为Null模式,将library cache pin以Exclusive模式获得后,创建executing plan. 2~3号过程称为hard parsing.
4) Oracle对Sql Cursor以shared模式获得library cache lock和library cache pin,并执行sql。但是执行修改对象信息(如DDL语句)工作时,对相应的对象所对应的LCO以Exclusive模式获得library cache lock和library cache pin。
5) oracle对执行结束的Sql Cursor Fetch数据。在Fetch阶段里,sql cursor将library cache lock变换为null模式,并解除library cache pin。Oracle concepts上将以null模式获得的library cache lock称为breakable parse lock.
每次发生Parsing时,均需要获得library cache latch,所以发生争用的概率相当高。library cache latch争用与系统性能有直接联系,所以Oracle为解决library cache latch争用提供了多种方法:
1)对于pl/sql内反复执行的sql cursor,只有在最初执行时parsing,之后没有soft parsing也可以执行。Oracle将sql cursor相应的LCO pin在SGA上,所以即便没有获得library cache latch也可以参考LCO.
2)提供在会话内部缓存LCO位置的功能。 这就是session cursor caching.Oracle将一个会话内执行连续3次以上sql cursor的位置(即library cache内位置)和sql文本,存储到PGA。即使这样,还是有soft parsing,需要获得library cache latch,但不用检索library cache结构,而直接找到LCO位置,所以能缩短获得library cache latch的时间,相应减少争用。
3.3 事务和OWI
3.3.1 事务的概要
完整地理解了事务,就等于完整理解了Oracle,所以要理解事务,需要理解Oracle所提供的控制功能、内部结构、算法。用户执行DML(即执行事务)操作在Oracle内部按如下顺序进行。
1)相应事务分配回滚段(undo segment).(如无适当的联机状态的回滚段,则等待enq:US-contention)
2) 分配回滚段后,在回滚段头上创建事务表slot(transaction table slot).
3) 创建事务表后会生成TXID(transaction ID),再将此TXID分配给当前事务。TXID通过v$transaction视图的XIDUSN、 XIDSLOT、 XIDSQN表现。
4) 事务对象的数据块载入高速缓冲区,在块头的ITL(Interestd Transaction List)上登记事务条目(transaction entry)。(enq:Tx-allocate ITL entry)
5) 将需要修改块的修改信息存储到PGA(Change Vector).修改一行时,一般分别创建撤销头块(change vector#1)、撤销块(change vector#2)、数据块(change vector#3)相应的change vector.进程将PGA的change vector以名为redo record(或redo entry)复制到重做缓冲区。(latch:redo copy、redo allocation、redo writing)
6) 将之前映像信息(before image)记录到撤销块,继而修改数据块,被修改的数据块变为脏状态。而且,高速缓冲区上创建关于已修改的数据块的CR(consistent read)块。(如果正修改的行被另外的事务所改变,等待enq:Tx-row lock contention)
7) 执行提交后给事务分配SCN,提交信息存储在重做缓冲区。(此步骤中,如何查找脏块并提交,是通过PGA的信息得知修改的块,然后检索LRUW列,找到了更改块信息吗,还是存在一个“事务已经修改的块”这样一个表??)
8) 回滚段头的事务表存储已成功提交的信息,解除包括TX锁在内地所有资源占有。
9) 重做缓冲区的的内容记录在重做日志文件上,修改的块之后被DBWR记录到 数据文件中。
事务相关的资源如图7所示
-----------------------------------81 图------------------------------------------------------
------------------------------------------------------------------------------------------------------
关于转储数据块,以了解数据块和撤销区域中的数据修改,书中有详细记录,略。
注意82页dump块信息中 1号事务 可能属于延迟块清除(Delayed block cleanout)的情况。要查看其是否提交,需查看回滚段头的事务表才能判断。
延迟块清除:已成功提交时,Oracle对事务引起修改的所有数据块的ITL不能一一提交处理。在修改的块中,将当前告诉缓冲区上的一部分执行提交,对于剩下的块只将被事务分配的回滚段头的事务表slot进行提交。实际上这些剩下的块最终被另外会话扫描时进行清除,这种机制成为延迟块清除。block cleanout就是解除块上设定的row level lock的意思。若发生cleanout,row level lock就会被解除,ITL信息(SCN、Flag、Lock byte等)会被更新。
注:Oracle的Row level lock不是宏观上存在的锁,在物理上是不存在的,而是相应[行修改与否+修改行的事务信息(ITL)+撤销区域的事务表slot+Tx锁]信息结合的一种逻辑性的锁。虽然row level lock是利用TX锁体现的,但是Tx锁自身不是Row level lock,而是多种信息结合后体现了row level lock. 对于各行谁在进行修改的目录或Meta信息,Oracle不会另行管理。想确认行是否被修改,只有直接访问相应行才能知晓。
3.4 段和OWI
3.4.1 段的概要
HWM:oracle 区分已用空间和未用空间的标志。
移动HWM的工作是通过HW锁得到保护的。(enq:HW-contention).同时多个会话对相同段添加大量数据时,频繁的HWM移动可能引起HW锁争用。Oracle提供的段空间管理方法分为FLM(手动管理)和ASSM(自动管理)。
3.4.2 手动段空间管理 FLM
使用FLM时,Oracle利用空闲列方法管理段空间。空闲列就是linked list形式 管理空闲块的方法。段头块上管理空闲列的头(header)和尾(tail)的位置。(pctfree,pctused)。
Oracle给每个段基本上分配一个主空闲列,创建几个进程空闲列,数量与创建时Freelist属性值相同。如果freelist属性值=1(default),则主空闲列起到进程空闲列的作用。如果主空闲列已没有空闲列,Oracle获得HW锁、移动HWM,以增加空闲块。进程在事务持续期间尽可能使用事务空闲列。使用结束的空闲块将重新返还给主空闲列。若段的进程空闲列的数量比引发事务的实际进程的数量少很多,则发生空闲列上的争用,因此可能发生等待(buffer busy wait)事件的现象。这是因为多个进程从相同空闲列上获得相同空闲块时会发生buffer lock争用。通过充分考虑进程数并指定足够大的freelist属性值,就能解决buffer lock争用问题。freelist值也与分配区时移动的HWM值有关(移动的HWM=freelists*BUMP_HIGHWATER_MARK_COUNT),故与buffer lock争用相同,HW锁争用引起的性能问题,可通过赋予足够大的freelist属性值,增加进程空闲列数量的方法解决问题。
Oracle为了减少空闲列争用,提供空闲列组(freelist group)功能。在RAC这样的多实例环境下,各实例分别使用不同的空闲列组,因而能能减少各实例间的空闲列争用。使用空闲列组后,还能减少对段头块的争用。
3.4.3自动模式的段空间管理ASSM
使用ASSM后就没有必要指定freelist属性,各块的状态是通过位图(bitmap)值管理的,从而实现空间管理的自动化。位图块通过3层的树管理:(root node、branch node、leaf node),一个leaf node管理DBA范围,dba范围就是不超过区范围的连续块的集合(16~1024个数据块)。数据块的剩余空间程度分为full、Unformated、0~25%free、25%~50%free、50%~75%free、75%~100%free等6个等级。pctused属性不再被使用,但是pctfree属性依然被使用。
----------------------------------95 图-----------------------------------------
---------------------------------------------------------------------------------------
ASSM设计非常适合RAC之类的多实例的环境下运行。利用树状位图块,空闲块的请求很自然地被分散,所以在多实例环境下也能保证出色的性能。
3.5 I/O和OWI
3.5.1 I/O摘要
想要理解与I/O相关的oracle性能问题,必须要理解Oracle中的I/O工作是由多层(layer)组成的事实。
1.应用程序层:select、insert、update、delete、truncate...
降低不必要的I/O。有效使用I/O也是应用程序要承担的任务。
parallel query、parallel dml、Nologging、Direct load、Direct read、解析函数(analytical function)、cluster、IOT、Partitoning、Bitmap Index...
2.Oracle内存层:buffer cache | PGA
因有效使用高速缓冲区,而物理I/O减少,I/O性能问题很自然地得到了解决。Oracle提供如下功能:
touch count为基础的有效的LRU算法
buffer pinning以减少不必要的latch争用
多重缓冲池:默认缓冲池被经常使用的对象使用,Keep bufer用于“比较”经常使用的对象,Recycle buffer被使用于频度低的对象。oracle 10g之前的版本,对于FTS方式读取的块,不会在读取瞬间马上增加touch count,因此经常被从高速缓冲区挤出,所以对于这种表应尽量使用keep buffer.
多种块大小
Direct path I/O:绕过buffer cache,parallel query,parallel dml等对于永久段使用direct path I/O,排序工作对临时段使用direct path I/O,LOB段拥有稍显独特的处理机制,这就是根据创建LOB列的storage属性指定使用direct path i/o还是conventional path i/o
3.Oracle段层:Datafile、tempfile、tablespace、segment
Oracle建议尽量使用异步I/O。遗憾的是,在许多操作系统上真正的异步I/O只用于裸设备。若不能使用异步I/O,应该使用OS级的Direct I/O(绕过OS的高速缓冲区,此时没必要使用裸设备,类似裸设备工作方式),使用裸设备可以提高I/O,但由于不能使用OS提供的高速缓冲区,可能反而使性能下降,因此应用程序的调优应放在首位,只有在I/O系统“真的”缓慢时I/O系统的性能改善才必要。
4.OS/裸设备层:Asynch I/O、Direct I/O、Raw device、Raid...
metalink;29676.1 裸设备
metalink: 500216.995 性能下降的讨论
30286.1 raid
3.5.6 Direct path I/O
将高速缓冲区内修改的块记录到数据文件是DBWR固有的工作。相反,绕过高速缓冲区写入工作由个别进程直接进行。由于不经过buffer cache,因此不存在伴随同步化的资源消耗。也不发生因争用引发的性能下降现象。若确定是direct path i/o出现性能问题,应把重点放在改善I/O自身性能
同时使用oracle高速缓冲区和OS的高速缓冲区,拒了解,这种双重缓冲无益于性能。
3.6 重做和OWI
3.6.1 重做概要
将DML引起的变化存于buffer cache之前,事先存到redo buffer。将buffer cache上的dirty buffer记录到datafile之前,将相应的重做记录从redo buffer记录到redo log files。
重做区域存储如下四种区域的修改数据
-回滚段头 (undo segment header)
-撤销块 (undo block)
-数据块头 (data segment header)
-数据块 (data block)
不创建对于数据块、撤销块的重做的操作....略
在快速修改大量数据时,才可以抑制创建redo
关于永久表执行dml,永久表+direc load operation,临时表的dml,各自怎么创建撤销和重做的测试:
....
...
..
.
3.6.2 重做缓冲区
在修改buffer cache的块之前,Oracle将重做记录存于redo buffer经过如下步骤
1)将数据修改事项在进程内存区(PGA)以Change Vector存储。Change Vector可视为保存着对于一个行修改的所有修改事项的集合体。(latch:redo copy)
2)确认当前自身SCN在所有进程所拥有的SCN中是否是最大的SCN。
3)请求redo allocation latch,确保redo buffer有存储重做记录的空间。若剩余空间不足,则请求redo writing latch,向LGWR请求将redo buffer信息记录到redo log files.直到LGWR在重做缓冲区上确保剩余空间为止,等待log c所需的空间后,就会释放redo allocation latch。
4)将PGA上创建的change vector 以重做记录形式复制到重做缓冲区上。结束后释放redo copy latch。
5)到Oracle 8i为止,redo allocation latch在整个系统只有一个,因此发生redo allocation latch争用可能性较高。Oracle 9i提供了对这个问题的解决方案:shared redo strands,每个strand使用不同的redo allocation latch.
3.6.3 重做日志
Oracle尽量把多个请求一次性地记录,这称作组提交(group commits)。