第5章 Buffer Cache与Shared Pool原理
5.1 Buffer Cache原理
Buffer Cache是Oracle SGA中的一个重要部分,通常的数据访问和修改都需要通过Buffer Cache来完成。当一个进程需要访问数据时,首先需要确定数据在内存中是否存在,如果数据在Buffer中存在,则需要根据数据的状态来判断是否可以直接访问还是需要构造一致性读取;如果数据在Buffer中不存在,则需要Buffer Cache中寻找最后的空间以装载需要的数据,如果Buffer Cache中找不到足够的内存空间,则需要出发DBWR去写出脏数据,释放Buffer空间。
5.1.1 LRU与Dirty List
LRU List 用于维护内存中的Buffer,按照LRU算法进行管理,数据库初始化时,所有的Buffer都被Hash到LRU List上管理。当需要从数据文件上读取数据时,首先要在LRU List上寻找free的Buffer,然后读取数据到Buffer Cache中;当数据被修改之后,状态变为Dirty,就可以被移动到Dirty List,Dirty List上的都是候选的可以被DBWR写出到数据文件的Buffer,一个Buffer要么在LRU List上,要么在Dirty List上存在,不能同时存在于多个list上。
Buffer Cache 原理图解:
(1)当一个Server进程需要读数据到Buffer Cache中时,首先必须判断该数据在Buffer中是否存在(图中①所示过程),如果存在且可用,则获取该数据,根据LRU算法在LRU List上移动该Block;如果Buffer中不存在该数据,则需要从数据文件上读取;
(2)在读取数据之前,Server进程需要扫描LRU List寻找Free的Buffer,扫描过程中Server进程会把发现的所有已经修改过的Buffer移动到CheckPoint Queue上(图中②所示过程),这些Dirty Buffer随后可以被写出到数据文件。
(3)如果CheckPoint Queue超过了阈值,Server 进程就会通知DBWn去写出脏数据(图中③所示过程);这也是出发DBWn写的一个条件,这个阈值曾经提到是25%,也就是当检查点队列超过25%满就会出发DBWn写操作;如果Server进程扫描LRU超过一个阈值仍然不能找到足够的Free Buffer,将停止查找,转而通知DBWn去写脏数据,释放内存空间。
同样这个阈值可以从以上字典表中查询到,这个数字是40%,也就是说当Server进程扫描LRU超过40%还没找到足够的Free Buffer就会停止搜索,通知DBWn执行写出,这个进程会处于 free busy wait等待。同时由于增量检查点的引入,DBWh也会主动扫描LRU List,将发现的Dirty Buffer移至CheckPoint Queue,这个扫描也受一个内部约束,在ORacle9iR2中,这个比例是25%。
(4)找到足够的Buffer之后,Server进程就可以将Buffer从数据文件读入Buffer Cache中(图中④所示过程)。
(5)如果读取的Block不满足一致性需求,则Server进程需要通过当前Block版本和回滚段构造前进行返回给用户;
可通过如下命令转储Buffer Cache的内容,从而清晰的看到以上描述的数据结构:
SQL>alter session set events 'immediate trace name buffers level 4';
不同level转储的内容详细程度不同,此命令的可用级别分为1~10级,各级别的含义如下:
-
Level1:仅包含Buffer Headers信息;
-
Level2:包含Buffer Headers和Buffer概要信息转储;
-
Level3:包含Buffer Headers和完整Buffer内容转储;
-
Level4:Level1+Latch转储+LRU队列;
-
Level5:Level4+Buffer概要信息转储;
-
Level6和Level7:Level4 + 完整Buffer内容转储;
-
Level8:Level4 + 显示Users/Waiters信息;
-
Level9:Level5 + 显示Users/Waiters信息;
-
Level10:Level6 + 显示Users/Waiters信息;
转储仅限于在测试环境中使用;
5.2 Shared Pool的基本原理
Oracle通过Shared Pool来实现SQL共享、减少代码硬解析等,从而提高数据库性能。
5.2.2 了解X$KSMSP视图
Shared Pool的空间分配和使用情况,可通过一个内部视图来观察,这个视图就是X$KSMSP。
5.2.4 Library Cache Pin和Library Cache Lock分析
Oracle使用两种数据结构来进行Shared Pool的并发访问控制:lock和pin.lock比pin具有更高的级别;
lock在handle上获得,在pin一个对象之前,必须首先获得该handle的锁定。锁定主要由3种模式:Null、Share和Exclusive.
在读取访问对象时,通常需要获取Null模式以及Share模式的锁定。在修改对象时,需要获得Exclusive(排他)锁定。
在锁定了Library Cache对象以后,一个进程在访问之前必须pin该对象。同样pin有3种模式:Null、Shared和Exclusive.只读模式时获得共享pin,修改模式获得排他pin.
通常访问、执行过程和Package时,获得的都是共享pin,如果排他pin被持有,那么数据库此时就要产生等待。
第6章 重做(Redo)
重做(Redo)和撤销(Undo)是Oracle的重要特性,用以保证事务的可恢复性和可撤销性。
6.1 Redo的作用
Oracle通过Redo来保证数据库的事务可以被重演,从而使得在故障之后,数据可以被恢复。
在数据库中,Redo的功能主要通过3个组件来实现:Redo Log Buffer、LGWR后台进程和Redo Log File.
Redo Log Buffer位于SGA中,是一块循环使用的内存区域,其中保存数据库变更的相关信息;
该信息以重做条目(Redo Entries)形式存储;Redo Entries的内容被Oracle数据库进程从用户的内存空间复制到SGA中的Redo Log
buffer之中。Redo Entries在内存中占用连续的顺序空间,由于Redo Log Buffer是循环使用的,Oracle通过一个后台进程LGWR不断的把Redo Log Buffer的内容写到Redo Log File之中。Redo Log File也是循环使用的。
缺省情况下,数据库创建时会创建3个日志组:
SQL>select group#,members,status from v$log;
当一个日志文件写满之后,会切换到另外一个日志文件,该过程称为Log Switch。Log Swith会触发一个检查点,促使DBWR进程将写满的日志文件的保护数据写回到数据库。在检查点完成之前,日志文件是不能够被重用的。
当检查点发生时,Oracle会通知DBWR进程,把修改过的数据,也就是此检查点之前的脏数据从Buffer Cache写入磁盘,在检查点完成后CKPT进程会相应的更新控制文件和数据文件头,记录检查点信息,标识变更。
在检查点完成之后,此检查点之前修改过的数据都已经写回磁盘,重做日志文件中的相应重做记录对于崩溃/实例恢复不再有用。
如果此后数据库崩溃,那么恢复只需要从最后一次完成的检查点开始恢复即可。如果数据库运行在归档模式,日志文件在重用之前必须写出到归档日志文件,归档日志在介质恢复时可以用来恢复数据库故障。
6.2 Redo的内容
改变向量表示对数据库内某个数据块所做的一次变更。改变向量中包含了变更的数据块的版本号、事务操作代码、变更从属数据块的地址以及更新后的数据。例如:一个Update事务包含一系列的改变向量,对于数据块的修改是一个向量,对于回滚段的修改又是一个向量。
重做记录通常由一组改变向量组成,是一个改变向量的集合,代表一个数据库的变更,构成数据库变更的最小恢复单位。例如:
一个Update的重做记录包括相应的回滚段的改变向量和相应的数据块的改变向量等。
6.3 产生多少Redo
(1)在sql*plus中使用autotrace时;
(2)通过v$mystat查询
Oracle通过v$mystat视图记录当前session的统计信息,也可以从该视图中查询得到session的Redo生成情况。
(3)通过v$sysstat查询
对于数据库全局的Redo生成量,可以通过v$sysstat查询到;
SQL>select name,value from v$sysstat where name='redo size';
6.4 Redo写的触发条件
LGWR写的触发条件有如下几种:
6.4.1 每3秒钟超时
当LGWR处于空闲状态时,它依赖于rdbms ipc message等待,处于休眠状态,直到3秒超时时间到。如果LGWR发现有Redo需要写出,那么LGWR将执行写出操作,log file parallel write等待事件将会出现。
6.4.2 阈值达到
两个触发日志写的条件是:
-
Redo Log Buffer 1/3满;
-
Redo Log Buffer 具有1MB的脏数据;
这两者都是限制条件,在触发时是协同生效的;
6.4.3 用户提交当一个事务提交时,在Redo Stream中将记录一个提交标识。在这些Redo被写到磁盘上之前,这个事务是不可恢复的。在事务返回成功标识给用户之前,必须等待LGWR写完成。进程通知LGWR写,并且以Log File Sync事件开始休眠,超时时间为1秒。
6.4.4 在DBWn写之前
如果DBWR将要写出的数据的高RBA超过LGWR的on-Disk RBA,则DBWR将通知LGWR去执行写出。
6.5 Redo Log Buffer的大小设置
Redo Log Buffer的大小由初始化参数LOG_BUFFER定义,该参数的缺省值如下:
Max(512kb,128kb * CPU_COUNT)
log_buffer参数的设置是否需要调整,可以从数据库的等待时间来判断:
SQL>select event#,name from v$event_name where name='log buffer space';
当log buffer space过多时,可适当增大log_buffer.
6.7日志的状态
可通过v$LOG视图来查看日志文件的状态:
SQL>select group#,status,first_change# from v$log;
最常见的状态有:CURRENT、ACTIVE、INACTIVE和UNUSED.
(1)CURRENT
CURRENT指的是当前的日志文件,该日志文件是活动的,当前正在被使用的,在进行崩溃恢复时,CURRENT的日志文件是必须的;
(2)ACTIVE
ACTIVE的日志是活动的非当前日志,该日志可能已经完成归档也可能没有归档,活动的日志文件在Crash恢复时会被用到。
(3)INACTIVE
INACTIVE的日志是非活动日志,该日志在实例恢复时不再需要,但是在介质恢复时可能会用到。INACTIVE状态的日志也可能没有被归档。如果数据库启动在归档模式,在未完成归档之前,日志文件也不允许被覆盖,这时候活动进程会处于log file switch等待之中。日志是否完成归档,可以根据V$LOG.ARCHIVED字段进行解析。
(4)UNUSED
UNUSED是指该日志从未被写入,这类日志可能是刚被添加到数据库或在RESETLOGS之后被重置,被使用之后,该状态会被改变。
6.8 日志的块大小
初始化参数LOG_BUFFER决定了Redo Log Buffer的大小,这个参数的缺省值为Max(512k,128k * CPU_COUNT).
LOG_BUFFER中的Redo Entries的大小以byte为单位;LGWR以Block为单位把Redo写入磁盘。
可通过内部视图查看Redo Block Size的大小,一般以512bytes为单位:
SQL>select max(lebsz) from x$kccle;
6.9 日志文件的大小
当日志文件发生切换时,会触发一个检查点,那么日志文件的大小和检查点的触发频率有关。
6.11 能否不生成Redo
6.11.1 NOLOGGING对数据库的影响
正常数据库必须生成Redo,这是数据库的机制,不然数据库遇到故障或Crash时则无法恢复。
NOLOGGING可使得生成日志幅度大大降低,但必要日志还是会记录。
关于NOLOGGING的作用,总结如下:
NOLOGGING与表模式(LOGGING/NOLOGGING)、插入模式(APPEND/NO APPEND)及数据库运行模式(归档/非归档)都有关系,
6.11.2 disable_logging对于数据库的影响
Oracle还有一个内部参数,可以使数据库关闭日志记录。这个参数是_disable_logging.
6.12 Redo故障的恢复
第7章 回滚与撤销
7.1 什么是回滚和撤销
Oracle用数据库中的回滚段(Rollback)来提供撤销数据(Undo Data);而Oracle还提供了一种新的撤销数据管理方式,就是使用Oracle自动管理的撤销表空间。
事务使用回滚段来记录变化前的数据或撤销信息;
在一个事务的进行过程中,Redo和Undo是交替出现的;
在事务开始时,首先需要在回滚表空间获得一个事务槽,分配空间,然后创建前镜像,此后事务的修改才能进行,Oracle必须以此来保证事务是可以回滚的。如果用户提交了事务,Oracle会在日志文件记录提交,并且写出日志,同时会在回滚段中把该事务标记为已提交;如果用户回滚事务,则Oracle需要从回滚段中把前镜像读取出来,修改数据缓冲区,完成回滚,这个过程本身也要产生Redo.
7.2 回滚段存储的内容
-
对于INSERT操作,回滚段只需要记录插入记录的rowid,如果回退,只需将该记录根据rowid删除即可;
-
对于UPDATE操作,回滚段只需要记录被更新字段的旧值(前镜像)即可,回退时通过旧值覆盖新值即可完成回退;
-
对于DELETE操作,Oracle则必须记录整行的数据,在回退时,Oracle会通过一个反向操作恢复删除的数据;
对于相同数据量的数据操作,通常INSERT产生最少的Undo,UPDATE产生的Undo居中,而DELETE操作产生的Undo最多。
7.3 并发控制和一致性读
一方面Oracle通过锁定机制来实现数据库的并发控制;一方面通过多版本模型来进行并发数据访问。通过多版本架构,Oracle实现了读取和写入的分离,使的写入不阻塞读取,读取不阻塞修改。
多版本模型在Oracle数据库中是通过一致性读来实现的,一致性读也正是回滚表空间的作用之一。
Oracle一方面不允许其他用户读取未提交的数据,一方面要保证用户读取的数据来自同一时间点。
Oracle内部使用SCN作为数据库时钟,这里查询结果集就是根据SCN来判断的,每个数据块头部都会记录一个提交SCN,当数据更改提交时,提交SCN同时被修改,这个SCN在查询时可以用来进行一致性读判断。
从Oracle9i开始,Oracle引入了自动管理的Undo表空间,如果选择使用自动的Undo表空间的管理,那么用户不再能够创建和删除回滚段,也不再需要为事务指定回滚段,这一切都由Oracle自动完成。
Oracle也引入了新的初始化参数:
-
undo_management:用来定义数据库使用的回滚段是否使用自动管理模式。该参数有两个可选项,AUTO表示自动管理,MANUAL表示手动管理;
-
undo_tablespace:用来定义在自动管理模式下,当前实例使用哪个Undo表空间;
-
undo_suppress_errors:表示当使用自动管理时,如果使用不再支持的操作时,是否返回出错信息。设置为true时不返回出错信息,操作无效但是可以继续,设置为False时,则操作不能继续,这实际上是一个向后兼容的参数;
-
undo_retention:表示在自动管理模式下,当回滚段变的非激活之后,回滚段中的数据在被覆盖前保留的时间,该参数单位为秒。在Oracle9iR2中,该参数的缺省值是3个小时。
在自动管理的Undo表空间下,回滚段的个数是Oracle根据数据库的繁忙程度自动分配或者回收的,缺省情况下,数据库创建时的初始化10个回滚段。可通过如下视图查询到:
SQL>select * from v$rollname;
在系统繁忙时,可从数据库的alert_.log文件中看到回滚段的动态创建和释放过程。
7.5 回滚机制的深入研究
ITL事务槽,事务必须获取一个ITL事务槽才能进行数据修改。ITL内容主要包括:
-
Xid: Transaction ID;
-
Uba:Undo block Address,指向具体的回滚段;
-
Lck: Lock Status;
一个事务内部流程如下:
(1)首先当一个事务开始时,需要在回滚段事务表上分配一个事务槽;
(2)在数据块头部获取一个ITL事务槽,该事务槽指向回滚段头的事务槽;
(3)在修改数据之前,需要记录前镜像信息,这个信息以UNDO RECORD的形式存储在回滚段中,回滚段头事务槽指向该记录;
(4)锁定修改行,修改行锁定位指向ITL事务槽;
(5)事务修改可以进行;
块清除:由于Oracle在数据块上存储了ITL和锁定等事务信息,所以Oracle必须在事务提交之后清除这些事务数据,这就是块清除。块清除主要清除的数据有行级锁、ITL(包括提交标识、SCN)信息。
延迟块清除:如果提交事务时,修改过的数据块已经被写回到数据文件上(或大量修改超过10%的部分),再次读出该数据块进行修改,显然成本过于昂贵,对这种情况,Oracle选择延迟块清除,等到下一次访问该Block时再来清除ITL锁定信息。
7.6 使用ERRORSTACK进行错误跟踪
ERRORSTACK是Oracle提供的接口,用于诊断Oracle的错误信息;诊断事件可以在session级设置,也可以在系统及设置,如果需要诊断全局错误,最好在系统级设置。设置了ERRORSTACK事件之后,Oracle会将出错的信息记入跟踪文件之中,用户就可以通过跟踪文件进行错误诊断和排查了。
7.8 Oracle10g 闪回查询特性的增强
Oracle10g提供了2种闪回查询:
-
闪回版本查询(Flashback Version Query)
-
闪回事务查询(Flashback Transaction Query)
闪回版本查询允许使用一个新的VERSIONS字句查询两个时间点或者SCN之间的数据版本。这些版本可以按照事务进行区分,闪回版本查询只返回提交数据,未提交数据不被显示。
阅读(1427) | 评论(0) | 转发(0) |