Oracle log buffer及日志管理深入分析及能调整.doc_第1页
Oracle log buffer及日志管理深入分析及能调整.doc_第2页
Oracle log buffer及日志管理深入分析及能调整.doc_第3页
Oracle log buffer及日志管理深入分析及能调整.doc_第4页
Oracle log buffer及日志管理深入分析及能调整.doc_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

log buffer及日志管理深入分析及性能调整1. log buffer的概念1.1 log buffer概述数据库在运行过程中,不可避免的要遇到各种能够导致数据块库损坏的情况。比如突然断电、oracle或者操作系统的程序bug导致数据库内部逻辑结构损坏、磁盘介质损坏等,都有可能造成数据库崩溃,从而导致数据丢失的现象发生。为了避免,或者说为了修复这些状况所导致的数据丢失现象,oracle引入了日志缓冲区和日志文件的概念。所谓日志,就是将所有数据库中所有改变数据块的操作,都原原本本的记录下来。这些改变数据块的操作不仅包括对数据表的DML或者对数据字典的DDL,还包括对索引的改变、对回滚段数据块的改变、对临时表空间的临时段的改变等。只有将数据库中所有的变化都记录下来,当发生数据库损坏时,才能够从损坏时的那一点开始,将之后数据库中的变化重新运用一遍,从而达到恢复数据库的目的。既然是要记录,那就必然引出一个问题,就是如何记录这些变化?比较容易想到的有两种方式。第一种是使用逻辑的记录方式,也就是用描述性的语句来记录整个变化过程。比如对于某个update更新操作来说来说,可以记录为两条语句:delete旧值以及insert新值。这种方式的优点是非常节省空间,因为对每个操作,只需要记录几条逻辑上的语句即可。但是缺点也很明显,就是一旦需要进行恢复,就会非常消耗资源。设想一下,某个update操作更新了非常多的数据块,由于buffer cache内存有限,很多脏数据块都已经写入了数据文件。但就在更新快结束时,突然发生断电,所做的更新丢失。那么重新启动实例时,oracle需要应用日志文件里的记录,于是重新发出delete旧值以及insert新值的语句。这个过程需要重新查找数据文件中符合条件的数据块,然后再挑出来进行更新。这个过程将非常消耗时间,而且会占用大量的buffer cache。第二种方式是使用物理的记录方式,也就是将每个数据块改变前的镜像和改变后的镜像都记录下来。这种方式优点就是恢复起来速度非常快,直接根据日志文件里所记录的数据块地址和内容更新数据文件中对应的数据块。但是缺点也很明显,就是非常占用磁盘空间。而oracle在记录日志的方式上,采用了逻辑和物理相结合的方式。也就是说,oracle针对每个数据块,记录了插入某个值或者删除某个值的描述语句。假如某个update更新了100个数据块,则oracle会针对每个数据块记录一对delete旧值和insert新值的语句,共有100对这样的描述语句。通过这种方式,oracle获得了物理记录方式的快速恢复的优点,同时又获得了逻辑记录方式的节省空间的优点。为了临时存放所产生的日志信息,oracle在SGA中开辟了一块内存区域。这块区域就叫做日志缓冲区(log buffer),当满足一定条件以后,oracle会使用名为LGWR的后台进程将log buffer中的日志信息写入联机日志文件里。可以使用初始化参数log_buffer来设置日志缓冲区的大小,单位是字节。日志缓冲区会进一步细分为多个块,每个块的尺寸与操作系统的一个块的尺寸相同,基本都是512字节。我们可以用如下方式来获得日志缓冲区的块尺寸。SQL select distinct lebsz as redo_block_size from x$kccle;REDO_BLOCK_SIZE- 512也可以用下面的方式来计算出日志缓冲区的块尺寸。SQL select round(a.redosize+b.redowast)/c.redoblks) + 16 as redo_block_size from 2 (select value redosize from v$sysstat where name=redo size) a, 3 (select value redowast from v$sysstat where name=redo wastage) b, 4 (select value redoblks from v$sysstat where name=redo blocks written) c 5 ;REDO_BLOCK_SIZE- 512日志缓冲区只是日志信息临时存放的区域,这块区域是有限的,而且其中的每个块都是能够循环使用的。这也就说明,日志缓冲区中的内容必须要写入磁盘上的文件里,才能永久保留下来,才能在数据库崩溃时能够用来进行恢复。这个文件就叫做联机日志文件。在每个日志缓冲区中的日志块被重用之前,其内容必然已经被写入了磁盘上的联机日志文件中。联机日志文件就是日志缓冲区的完全拷贝,组成日志文件的每个日志块的内容都来自于日志缓冲区的日志块。每个日志缓冲区中的日志块都对应到日志文件中的一个日志块。日志缓冲区中的日志块按照发生的先后顺序,放入联机日志文件。由于日志文件在故障恢复中的重要性,建议至少使用两个日志文件组成一个日志文件组。同一个日志文件组中的日志文件内容一摸一样,因为日志缓冲区中的日志块同时会写入日志文件组中的每个日志文件中。每个数据库都必须至少拥有两个日志文件组。这是由于只要数据库一天不停止运行,就会不断产生日志信息,就会不断写入联机日志文件,联机日志文件总会有写满的时候。我们不可能让联机日志文件无限大,也不可能放无限多的联机日志文件,所以联机日志文件必须是循环使用的,在若干个日志文件中轮流的进行写入。一个日志文件写满以后转换到另外一个日志文件继续写的过程叫做日志切换(log switch)。当一个联机日志文件写满时,可以选择将其归档为脱机日志文件,通常叫做归档日志文件。归档也就是拷贝,归档的过程也就是将写满的联机日志文件拷贝到预先指定的目录的过程。只有当一个联机日志文件完成归档以后,该联机日志文件才能够被再次循环使用。强烈建议在生产库中选择这种归档方式,只有在测试环境中可以不选择这种归档方式。可以说,日志缓冲区和日志文件存在的唯一目的就是为了保证被修改的数据不会被丢失。反过来说,也就是为了能够在数据库崩溃的时候,可以用来将数据库恢复到崩溃的那个时间点上。这也就是说,只有将被修改的数据块的日志信息写入了联机日志文件以后,该被修改的数据块才可以说是安全的。如果日志信息在没有被写入日志文件时发生实例崩溃,这时对数据的修改仍将丢失。由此我们可以看出,将日志缓冲区中的日志信息写入日志文件是一个多么重要的过程,这个过程是由一个名为LGWR的后台进程完成的。LGWR承担了维护系统数据完整性的任务,它保证了数据在任何情况下都不会丢失。触发LGWR进程将日志缓冲区中的日志信息写入联机日志文件条件包括以下几种:1.前台进程触发,包括两种情况。最显而易见的一种情况就是用户发出commit或rollback语句进行提交时,需要触发LGWR将内存里的日志信息写入联机日志文件,因为提交的数据必须被保护而不被丢失;另外一种情况就是在日志缓冲区中找不到足够的内存来放日志信息时,也会触发LGWR进程将一些日志信息写入联机日志文件以后,从而释放一些空间出来。2.每隔三秒钟,LGWR启动一次。3.在DBWR启动时,如果发现脏数据块所对应的重做条目还没有写入联机日志文件,则DBWR触发LGWR进程并等待LRWR写完以后才会继续。4.日志信息的数量达到整个日志缓冲区的1/3时,触发LGWR。5.日志信息的数量达到1MB时,触发LGWR。6.发生日志切换时触发LGWR。1.2 log buffer的内存结构我们已经知道,日志缓冲区用来存放事务对数据块的改变的日志信息。那么这里的日志信息到底包含哪些内容,是由哪些结构组成的呢?oracle记录数据库变化(也就是记录日志信息)的最小单位是改动向量(change vector)。改动向量用来描述对数据库中任何单个数据块所做的一次改动。改动向量的内容包括:被改动的数据块的版本号、事务操作代码、被改动的数据块的地址等。这里的版本号非常重要,它能够帮助数据块始终能够体现当前最新的状态。oracle在建立改动向量时,会从数据块中拷贝其版本号。而当恢复期间,oracle读取改动向量并将改动应用于相应的数据块以后,被恢复的数据块的版本号加1。这里的数据块可以属于表、也可以数据索引、也可以属于回滚段。但是对于临时表空间里的临时段,不会生成改动向量。当多个改动向量按照先后顺序组合在一起,从而完成对数据库的一次改动时,oracle称这组改动向量为重做记录(redo record)。重做记录用来描述对数据库的一个原子改动。所谓原子改动,就是说,当应用改动中的改动向量时,要么全部成功,要么全部失败,不存在部分成功部分失败的情况。重做记录能够帮助整个数据库体现当前最新的状态。一个事务至少产生一个重做记录,也可能产生多个重做记录。而oracle在应用日志记录进行恢复的过程中,以事务作为恢复的最小单位。要么恢复整个事务,要么回滚整个事务。也就是说,要么运用事务中的重做记录里的所有改动向量,要么一个改动向量都不运用。因此,日志缓冲区就是许多重做记录按照发生的先后顺序组成的。同时,日志文件也就是由许多重做记录按照先后顺序排列在一起而组成的文件。我们举个实例来说明重做记录和改动向量产生的过程。比如我们发出如下更新语句(假设表redo_test的name列上没有建立索引):SQL select * from redo_test; ID NAME- - 1 abc 2 abcSQL update redo_test set name=cdf where id=1;该语句发出以后,会产生一个重做记录,用来描述对表的数据块的修改。包括下面三个改动向量:1.对回滚段事务表的改动,这发生在回滚段段头。事务表中包含被修改的数据块的地址、该事务的状态(commit或active)、以及存有该事务所使用的回滚段的地址。如果事务表被修改,就会产生针对于它的改动向量。2.对回滚段数据块的改动。将修改前的旧值(abc)存放到回滚段的数据块里。这时回滚段发生改变,于是产生改动向量。3.对redo_test表的数据块所做的改动。将修改后的新值(cdf)存放到表的数据块里。这时数据块发生改变,于是产生改动向量。从这个实例可以知道,对于这个update事务,重做记录中会有三个改动向量。当然可能有其他情况会产生新的重做记录,比如修改的列如果有索引,则必须修改索引。这时就会产生第二个重做记录,用来描述对索引数据块的修改。这时候的重做记录还是和第一个重做记录一样,包含多个改动向量。此外,在事务完成之后运行commit或rollback语句时,就会产生第三个重做记录。该重做记录只有一个改动向量,用来记录对回滚段事务表的更改,因为commit或rollback时,需要更新事务表里记录的该事务的状态。1.3转储log bufferoracle对很多内存结构都提供了转储到平面文件的功能,但是并没有直接提供转储日志缓冲区的功能。但是提供了转储日志文件的功能。我们前面已经知道,日志文件的内容就是日志缓冲区的完全拷贝,因此,转储日志文件就等于转储了日志缓冲区。转储日志文件的命令为:alter system dump logfile logfilename;我们的实验过程如下。首先找到当前状态为CURRENT的日志文件是哪一个,以及它的全路径。SQL select group#,status from v$log; GROUP# STATUS- - 1 INACTIVE 2 INACTIVE 3 CURRENTSQL select member from v$logfile where group#=3;MEMBER-/oracle/oradata/ora10g/redo03.log然后,找到我们的redo_test表的object id,并进行更新操作。SQL desc redo_test Name Null? Type - - - ID NUMBER NAME VARCHAR2(10)SQL select object_id from user_objects where object_name=REDO_TEST; OBJECT_ID- 51367SQL select * from redo_test; ID NAME- - 1 abc 2 abcSQL update redo_test set name=cdf where id=1;SQL commit;最后,我们转储出当前使用的日志文件。SQL alter system dump logfile /oracle/oradata/ora10g/redo03.log;打开生成的跟踪文件,从中找到含有51367(表redo_test的object id)的所有相关记录,如下图所示。 图一我们可以看到,第一行明确说明了,下面的内容都属于同一个重做记录(REDO RECORD)。往下可以看到的CHANGE #的字样,这里的CHANGE #就表示改动向量(CHANGE VECTOR),我们可以看到一共生成了四个改动向量(第3、15、18、21行)。正像我们前面所描述的那样,第一个是对回滚段事务表的改动(CHANGE #2),第二个是对回滚段数据块的改动(CHANGE #4),第三个是对redo_test表的数据块的改动(CHANGE #1),第四个是提交时对回滚段事务表的改动(CHANGE #3)。注意,这里的CHANGE #后面的数值并不表示发生顺序,只不过是一个标识而已,发生的先后顺序要以SCN号为准,SCN号越小的表示越早发生。另外一个需要注意的是,在这个例子里,第四个提交时对回滚段事务表的改动(CHANGE #3)的改动向量并没有单独成为一个重做记录,这是因为我们发出update语句以后立即提交了。如果发出update语句以后,不立即提交,而是等待一段时间,然后再提交。这时转储出来的日志文件会显示出两个重做记录,最后的提交时对回滚段事务表的改动的改动向量会单独归到一个重做记录里去。后面会说明原因。第8行的slot: 0表示被更新的记录位于数据块中的第一行。这与第35行的slot是一样的。如果我们发出“update redo_test set name=cdf where id=2”时,就会发现这时slot为1。第9行的size: 0表示修改后的值的长度减去修改前的值的长度的结果。而第36行的size表示修改前的值的长度减去修改后的值的长度的结果。由于我们这里修改前后的值的长度都是3,所以差额为0。如果我们发出“update redo_test set name=cdfg where id=1”时,就会发现第9行的值为1,第36行的值为-1。第11行的bdba表示redo_test表的数据块的地址,其实就是第3行的DBA所显示的地址。而hdba则表示redo_test表的segment header的地址。与第38行的值是相同的。第14行的col 1表示被更新的是表的第二列(第一列是col 0)。后面的3表示该列的值的长度,单位是字节。它们与第41行的内容是相同的。再后面的63 64 66则表示col 1列被更新后的值。我们来转换一下,如下所示。可以看到这正是我们更新后的“cdf”值。同样我们可以看到第41行的61 62 63,表示更新前的值,也就是“abc”。SQL select chr(to_number(63,xx),chr(to_number(64,xx), 2 chr(to_number(66,xx) from dual;C C C- - -c d f第15行的DBA: 0x00800009表示回滚段事务表的地址,这与第18行的DBA是一样的。由于回滚段事务表位于回滚段段头里,所以这也就是回滚段段头的地址。008表示文件号乘以4,00009表示数据块地址。我们转储出该段头来看看里面放了些什么。SQL select to_number(008,xxx)/4 file#, 2 to_number(00009,xxxxx) block# from dual; FILE# BLOCK#- - 2 9SQL alter system dump datafile 2 block 9;我们打开所生成的跟踪文件,可以看到存放的正是回滚段事务表的信息。如下图二所示。我们可以看到粗体显示的正是我们发出的update语句在事务表中所登记的条目,state为9表示事务已经提交。 图二第17行的uba: 0x0080085a.0075.13表示存放redo_test被更新前旧值的回滚段数据块所在的地址,这与第20行的uba是一样的。0080085a表示回滚段数据块所在的地址,0075表示顺序号,13表示在回滚映射中的最后一个条目。我们只需要关心0080085a即可,其组成部分和前面所介绍过的是一样的,008表示文件号乘以4,0085a表示回滚段数据块的地址。SQL select to_number(008,xxx)/4 as file#, 2 to_number(0085a,xxxxx) as block# from dual; FILE# BLOCK#- - 2 2138SQL alter system dump datafile 2 block 2138;然后,打开生成的跟踪文件,找到含有51367(表redo_test的object id)的相关记录,如下图三所示。 图三从上图中我们可以看到熟悉的bdba和hdba。以及最后一行的61 62 63,这就是更新前的旧值。同时我们还可以注意到KDO Op code: 21,这表示事务所进行的操作的类型代码。因为我是在10g环境下测试的,所以这里显示了代码21,就表示进行的是update操作。如果在10g以前,会显示URP字样。2. log buffer的内部管理机制日志缓冲区的内部管理分为两部分,一部分是重做记录的生成,另一部分就是重做记录写入联机日志文件。这两部分不是孤立的,没有关联的。在生成重做记录的过程中,可能会触发LGWR将重做记录写入联机日志文件。我们先用一个实例来说明在日志缓冲区中的操作过程,并使用file# , blk#来表示某个数据块,file#表示文件号,blk#表示数据块号。假设session 1发出更新语句:update redo_test set name=cdf where id=1; Oracle首先找出id=1所在的数据块(假设为file#4,blk#120)放入buffer cache,然后找出一个可用的回滚段数据块(假设为file#2,blk#19),将旧值abc放入该块,同时生成重做记录。然后将cdf放入表的数据块,再生成重做记录。这时的日志缓冲区的结构类似如下。(我们从前面描述日志缓冲区的内存结构时,知道重做记录中最重要的就下面列的这几列内容。同时,下面的一行就表示一个改动向量):行号 事务id file# block# row column value1 T1 2 19 - - abc2 T1 4 120 1 2 cdf 这时假设session 2发出其他更新语句:update t set c1=10 where c1=9; 同样的道理,oracle找到该数据块(假设为file#5,blk#200)放入buffer cache,并找到回滚段数据块(假设为file#2,blk#30)存放旧值,生成重做记录,更新表的数据块,再次生成重做记录。这时的日志缓冲区的结构类似如下:行号 事务id file# block# row column value1 T1 2 19 - - abc2 T1 4 120 1 2 cdf3 T20 2 30 - - 94 T20 5 200 20 1 10这时,session 1又发出更新语句:update redo_test set name=xyz1 where id=2,并提交(commit)。同样的方式处理回滚段和数据块,并生成重做记录。假设这时生成日志缓冲区假设为:行号 事务id file# block# row column value1 T1 2 19 - - abc2 T1 4 120 1 2 cdf3 T20 2 30 - - 94 T20 5 200 20 1 105 T1 2 19 - - abc6 T1 4 120 2 2 xyz17 T1 commit SCN timestamp 这时,我们可以注意到,提交标记也被记录到了重做记录中。从我们前面转储出的结果中也可以看到“sta: 9”的内容,这就是提交标记。每次提交时,都会生成一个SCN号,SCN号越小,说明发生的越早,其所属的重做记录就越排在前面。一旦用户发出commit语句,系统就会触发LGWR进程。这时,LGWR进程会将上面所显示的所有重做记录都写入联机日志文件中。注意,其中也包括尚未提交的事务T20。 在LGWR写这些重做记录的过程中,又有其他session发出更新语句,并提交。这时的日志缓冲区假设如下所示:行号 事务id file# block# row column value1 T1 2 19 - - abc2 T1 4 120 1 2 cdf3 T20 2 30 - - 94 T20 5 200 20 1 105 T1 2 19 - - abc6 T1 4 120 2 2 xyz17 T1 commit SCN timestamp 以上的重做日志正在由LGWR写入-8 T20 2 39 - - 289 在LGWR写时生成以下的重做日志9 T20 5 498 220 3 19010 T9 2 90 - - hhh11 T9 9 100 20 9 xxx12 T9 commit SCN timestamp13 T18 2 189 - - 1814 T18 10 29 300 10 2015 T18 commit SCN timestamp当LGWR写完第一批重做记录(第1到第7行)以后,就会立即开始写第二批重做记录(第8行到第15行)。注意,第二批重做记录中,存在两个commit,但LGWR不会分成两次来写,而是一次就将它们全部写入。当LGWR在写完第1到第7行的改动向量以后,这部分的日志缓冲区内存就被释放了,可以被新生成的重做记录所覆盖。如果当前联机日志文件写完时,这时就需要转换到另外一个可写的联机日志文件上去,这个过程叫做日志切换。日志切换的大致过程包括:1.从控制文件中得到下一个可用的联机日志文件。2.记录写入当前联机日志文件的最后一个日志块的SCN(叫做high SCN)。关闭当前联机日志文件。3.增加SCN,再次操作控制文件,将下一个联机日志文件标志为CURRENT,判断前一个联机日志文件里包含的重做记录所对应的脏数据块是否都已经写入数据文件,如果没有则标记为ACTIVE;如果是则标记为INACTIVE。如果数据库是归档模式,那么LGWR将前一个联机日志文件加入归档列表中,等待归档。4.打开新的联机日志文件组中的所有成员,记录当前日志序列号(log sequence)和第一个日志块的SCN(叫做low SCN),新一轮的重做记录开始。我们经常看到当前日志文件的状态为CURRENT,而前一个日志文件的状态为ACTIVE的情况。实际上,这是由于内存中存在很多脏数据块,而脏数据块的写入是通过DBWR进程完成的。如果脏数据块没有积累到一定的量,DBWR是不会将它们写入数据文件的。所以,ACTIVE状态的日志文件表示该日志文件里包含的重做记录所对应的脏数据块还没有被DBWR进程写入数据文件。事实上,日志切换时触发增量检查点(incremental checkpoint),CKPT将会触发DBWR写脏数据块。增量检查点只是在控制文件中记录这时在检查点队列上的脏数据块在第一次修改时所对应的日志块在日志文件中的地址,这个地址叫做检查点位置(checkpoint position)。但是DBWR启动并不表示立即写脏数据块,除非脏数据块的数量达到一定程度,或超过一定时间等。我们来模拟一下这种情况。SQL select group#,status from v$log; GROUP# STATUS- - 1 CURRENT 2 INACTIVE 3 INACTIVESQL create table t2 as select * from dba_objects;SQL select group#,status from v$log; GROUP# STATUS- - 1 ACTIVE 2 CURRENT 3 INACTIVE我们可以看到,当创建了表t2的时候,发生了日志切换。如果没有看到日志切换,可以再删除表t2然后再创建表t2,如此反复几次,就能够引起日志切换。这时我们看到2号日志文件为当前打开的日志文件,其状态为CURRENT。而1号日志文件为上次打开的日志文件,状态为ACTIVE,就说明其对应的脏数据块还没有写入数据文件。这时我们可以等待一段时间,等待增量检查点的完成,也可以手工触发完全检查点(complete checkpoint),触发完全检查点时,DBWR将把所有脏数据块写入磁盘上的数据文件里。SQL alter system checkpoint;SQL select group#,status from v$log; GROUP# STATUS- - 1 INACTIVE 2 CURRENT 3 INACTIVE可以看到,1号日志文件的状态从ACTIVE变成了INACTIVE,说明其对应的脏数据块都已经写入了联机日志文件中。这里要说明一点。增量检查点触发的DBWR写和完全检查点触发的DBWR写的优先级是不一样的,这也就是为何在上面的例子中进行日志切换以后,前一个日志的状态为ACTIVE,而且要等一段时间以后其状态才能变为INACTIVE,而我们发出alte system checkpoint以后立即变为INACTIVE的原因。因为日志切换触发增量检查点,而增量检查点通知DBWR启动,但是由于这时触发DBWR启动的条件的优先级较低,所以DBWR不会立即去写脏数据块,而是要等一段时间才会实际的写脏数据块。所以我们等待日志状态变为INACTIVE的时间就是等DBWR开始真正写的时间加上DBWR实际写入数据文件所花费的时间。而alte system checkpoint触发完全检查点,其优先级很高,所以通过它触发的DBWR会立即去写脏数据块,所以我们等待日志状态变为INACTIVE的时间就是DBWR实际写入数据文件所花费的时间。我们可以设定初始化参数:log_checkpoints_to_alert为true,从而将检查点启动和结束的时间记录到跟踪文件里去。这里是所记录的信息的一个例子:Wed Dec 13 18:27:48 2006Beginning log switch checkpoint up to RBA 0x85.2.10, SCN: 2164686(这里有SCN哦)Thread 1 advanced to log sequence 133 Current log# 3 seq# 133 mem# 0: /oracle/oradata/ora10g/redo03.logWed Dec 13 18:32:45 2006Completed checkpoint up to RBA 0x85.2.10, SCN: 2164686Wed Dec 13 19:02:15 2006Beginning global checkpoint up to RBA 0x85.883.10, SCN: 2165818Completed checkpoint up to RBA 0x85.883.10, SCN: 2165818从上面可以看到,由于日志切换而发生的增量检查点从18:27:48开始,到18:32:45结束,用了5分钟的时间。而我们强制进行完全检查点,则只用了大概1秒钟不到的时间。实际上,DBWR在实际写入数据文件所花费的时间都是一样的,也就是不到1秒。5分钟的差别就在于DBWR等了5分钟才实际开始写数据文件。在大致了解了日志缓冲区的操作过程以后,我们来深入了解一下其内部的工作原理是怎样的。当用户发出DML语句,请求更新某些表里的数据时,在日志缓冲区中生成重做记录的过程如下所示。1.服务器进程判断buffer cache中是否存在要求被更新的数据块,如果没有,则从数据文件中将数据块调入buffer cache。然后以排他(Exclusive)模式将该数据块钉住(ping)。注意,这里的数据块包括回滚段段头(事务表)、回滚段数据块以及表所对应的数据块等。2.服务器进程构造一组改动向量(change vector)来描述对数据块所做的变化过程。这组改动向量会放在session的PGA中。实际上,这组改动向量也就是重做记录了。3.根据重做记录的大小,判断在日志缓冲区中需要多少空间。4.判断当前的SCN值,并将其存放到重做记录中。注意,并不是每个重做记录都具有不同的SCN值,不同的重做记录可能会共享相同的SCN值。5.进程获得名为redo copy的latch。6.进程获得名为redo allocation的latch。7.检查当前是否有其他进程生成了比当前持有的SCN更高的SCN值。如果是,则生成一个新的SCN值,并代替第四步所持有的SCN值。8.判断是否有足够的空间容纳当前的重做记录,这里足够的空间既包括日志缓冲区,也包括联机日志文件。这时的逻辑比较复杂。8.1.如果联机日志文件中有足够的空间,则判断日志缓冲区是否有足够的空间。8.1.1.如果日志缓冲区中没有足够的空间,则进程释放redo copy latch和redo allocation latch。然后在下面的两个选项中做一个选择:(1)如果这时已经有其他进程或其他条件触发了LGWR,则等待LGWR的完成;(2)如果这时LGWR没有启动,则触发LGWR启动。为了防止多个进程同时触发LGWR,oracle还引入了名为redo writing的latch。当LGWR进程在写重做记录到联机日志文件的过程中,会一直持有redo writing latch,这时任何试图获得该latch的进程都必须等待。实际上,当进程发现没有足够的空间以后,会立即尝试获取redo writing latch。如果不能获得该latch则说明LGWR正在清空日志缓冲区,所以进程会等待,过一段时间再次尝试去获得该latch;如果获得了该latch,则立即检查这时日志缓冲区中是否还有足够的空间,如果有,则释放redo writing latch,并再次尝试获得redo copy latch和redo allocation latch;如果没有,则释放redo writing latch,同时触发LGWR,这时LGWR获得redo writing latch。8.1.2.如果日志缓冲区中有足够的空间,则从日志缓冲区中分配所需大小的空间,然后释放redo allocation latch,注意这时仍持有redo copy latch。将改动向量拷贝到所分配的日志缓冲区中,将重做记录所对应的脏数据块挂到检查点队列(checkpoint queue)上去。最后,释放redo copy latch。8.2.如果联机日志没有足够的空间(可能有一部分可用空间,但是不够用。实际这就是有时你会看到归档日志文件的尺寸会小于联机日志文件的尺寸的原因),则进程会检查是否已经有进程已经触发日志切换了,如果有,则当前进程等待,如果没有则触发日志切换。然后,重复第8步。9.当在日志缓冲区中写完重做记录以后,检查当前日志缓冲区中的重做记录的数量是否达到限定值,如果是,则必须触发LGWR进程。10.最后,进程更新buffer cache中的数据块。我们可以用一个图来描述一下上面所说的日志缓冲区的管理过程,如下图四所示。图四上面详细介绍了重做记录的生成过程,现在详细介绍一下LGWR写重做记录的过程。当LGWR进程启动时,1.首先会尝试获取redo writing latch,以确保其他前台进程不会继续触发LGWR进程。2.然后会获取redo allocation latch,这是为了防止前提进程继续分配更多的日志缓冲区,否则日志缓冲区中的待写入日志文件的日志块不断增长,LGWR是无法确定到底应该写多少日志块的。3.在获得了redo allocation latch以后,LGWR开始确定应该写哪些日志块到日志文件。从上次LGWR启动以来所写的最后一个日志块到这个时间点时的最后一个被使用的日志块,这段范围内的日志块都是要被写入日志文件的,其中既包含写满的日志块,也可能包含还没有写满的日志块。特别注意,这个时候,可能还有前台进程正在向这段范围中的日志块拷贝重做记录。因为LGWR启动时,并不会阻碍前台进程获得redo copy latch,也就不会阻碍前台进程拷贝重做记录了。这样的话,LGWR就不会阻碍前台进程向日志缓冲区的其他可用的日志块中拷贝重做记录了。4.在确定了要写哪些日志块以后,生成一个新的SCN号。5.LGWR释放redo allocation latch,并释放redo writing latch。6.LGWR会等待前台进程完成对LGWR所要写入文件的日志块的更新操作。这是通过判断这些待写的日志块上的redo copy latch是否都被释放来决定的。7.LGWR将第4步生成的SCN号拷贝进待写的日志块的块头里,触发物理写操作,将这些待写日志块写入联机日志文件里去。3. log buffer的优化我们一般不太会关注日志缓冲区的优化。这是因为日志缓冲区的争用一般不会是数据库的主要性能问题。前面我们已经知道,日志块的都是按照顺序往里写,不存在更新日志块的以前的内容,同时每个日志块大小都很小,所以几乎不会有多个进程抢同一个日志块的情况。其争用主要是进程由于找不到可用的日志块而必须等待的情况。而我

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论