第9章 重做日志管理
重做日志是对用户的DML和DDL操作所做的记录,它是保证数据库安全的一种重要手段。当用户执行DML或DDL命令时,数据库服务器将生成重做日志,并将其记录在重做日志文件中。为了保证重做日志文件的安全,需要对它们进行归档。如果数据库出现故障,可以利用重做日志文件和归档日志文件进行实例恢复或者介质恢复。无论是重做日志文件还是归档日志文件,都是以二进制的形式记录重做日志的。用户如果需要了解这些文件的内容,就需要对它们进行分析,将日志信息转化为文本形式。
本章的主要内容包括重做日志文件的管理、归档日志文件的管理以及日志分析等内容。与重做日志有关的内容较多,接下来我们首先对这些内容做一次综合介绍,以使大家对重做日志有一个全面、深刻的认识。
当用户执行SQL语句时,在用户进程和服务器进程之间需要建立一条连接。用户进程向服务器进程发送SQL语句,服务器进程对这些SQL语句进行解析,并生成执行计划,然后将解析代码和执行计划存储在SGA的库缓冲区中,然后按照执行计划执行SQL语句。在执行阶段,服务器进程首先检查用户访问的数据是否已经位于数据库高速缓存中。如果是,则直接在数据库高速缓存的缓冲区中访问数据,否则,需要从数据文件中将对应的数据块读到数据库高速缓存中。如果用户的SQL命令是DML或DDL,那么在访问数据之前首先生成重做日志,并将重做日志记录在重做日志缓冲区中,然后修改数据库高速缓存中的缓冲区。被修改的缓冲区叫做脏缓冲区。
重做日志缓冲区是SGA的一部分,它的作用是记录数据库中的重做日志。重做日志是对用户执行的DML或DDL操作的记录,其中包括被修改的数据块、修改的位置以及修改后的数据等信息。重做日志缓冲区的大小由初始化参数LOG_BUFFER指定。当实例启动时,在内存中按照这个参数的值为重做日志缓冲区分配内存空间。
从上面的描述可以看到,当用户在修改数据时,服务器进程首先生成重做日志,然后才修改缓冲区中的数据。无论是重做日志还是被修改后的数据,都是位于内存中的。由于内存中的数据是易消失的,Oracle提供了两个后台进程,用于将这些数据写入磁盘上的文件中。其中DBWR的作用是在一定的时机下将数据库高速缓存中的脏缓冲区写入数据文件,LGWR进程的作用是在一定的时机下将重做日志缓冲区中的内容写入重做日志文件。DBWR和LGWR进程的执行时机并不是同步的,但是在DBWR工作之前,LGWR一定将重做日志写入了重做日志文件中。
用户在进行一次数据访问时,尽管被修改的数据可能已经写入了数据文件,重做日志也可能写入了重做日志文件,但这次访问并不一定是一个有效的事务,因为对数据库所做的任何修改都必须同时记录在数据文件、控制文件和重做日志文件中。Oracle是通过SCN来维护这个一致状态的。数据库服务器每执行一个事务,都将产生一个新的、递增的SCN。如果用户没有提交事务,新的SCN是不被写入任何一个文件的。这时如果系统突然断电,那么数据库服务器在重新启动时,SMON后台进程将检查数据文件、控制文件和重做日志文件中的SCN,并回滚所有的未提交事务,然后打开数据库。
如果用户在访问数据之后提交了事务,那么重做日志缓冲区的重做日志连同最新的SCN一起被写入重做日志文件。既然SCN和重做日志一起被写入了重做日志文件,实例恢复和介质恢复就成为可能。如果发生了系统掉电或者数据文件损坏等情况,可以根据重做日志文件的内容对数据库中的数据进行恢复。
用户提交事务后,最新的SCN仅仅写入了重做日志文件,而数据文件和控制文件中SCN的写入则依赖于检查点。检查点是一种数据库事件,当数据库服务器发生检查点时,DBWR进程将数据库高速缓存中的所有脏缓冲区写入数据文件,并且使数据文件、控制文件和重做日志文件中的SCN达到一致状态。检查点是由后台进程CKPT发出的,CKPT进程在一定的时机下发生检查点,同步数据文件、控制文件和重做日志文件的状态。
假设在用户提交事务后CKPT进程恰好发出一个检查点,这时三种文件的状态完全一致,如果这时系统突然断电,那么数据库服务器在重新启动时,可以直接打开数据库,不需要进行实例恢复,所以这次启动会很快。
如果在用户提交事务后CKPT还没有来得及发出检查点时系统突然断电,那么数据库服务器在重新启动时就需要进行实例恢复。在这种情况下,数据文件和控制文件中的SCN应该是一致的,并且小于重做日志文件中的SCN。SMON后台进程将检测到三个文件中的SCN不一致,于是将两个SCN之间的所有已经提交的事务重新执行一遍,并回滚所有未提交的事务,然后再打开数据库。Oracle利用这种方法来保证用户已经提交的事务不受系统故障的影响。
当用户执行DML操作时,服务器进程将修改前的数据首先写入回滚段,然后在数据库高速缓存中对数据进行修改。如果用户提交了事务,回滚段中的数据成为无效数据。如果用户回滚了该事务,那么回滚段中的数据将被写回原来位置,用户对这些数据所做的修改便宣告无效。
因为重做日志缓冲区的大小是有限的,而且它不能永久存储数据,因此重做日志需要被写入重做日志文件。在数据库中一般有若干个重做日志组,每个日志组中有若干个日志成员,数据库服务器以循环的方式将重做日志写入这些重做日志组。当一组重做日志文件被写满后,数据库服务器自动切换到下一个日志组。当最后一组重做日志文件被写满后,数据库服务器又自动切换到第一组。
在数据库服务器切换日志时,新的重做日志被写入重做日志文件,文件中原来的内容将被覆盖。为了保留以前的重做日志,需要对重做日志文件进行归档。重做日志文件的归档是由后台进程ARCH完成的。
9.1 重做日志的规划
在创建数据库之前,对重做日志进行详细的规划是很有必要的。重做日志的规划包括重做日志缓冲区规划、重做日志组规划以及重做日志文件的规划。通过对重做日志进行规划,不仅可以提高数据库系统的性能,而且能够保证重做日志的安全。
9.1.1 重做日志缓冲区的规划
当用户执行一个事务时,服务器进程首先生成重做日志,并记录在重做日志缓冲区中,而不是将其直接写入重做日志文件中,这样做的好处当然是因为内存的读写速度比硬盘快得多。在重做日志缓冲区中可以存储多条重做日志,LGWR后台进程在一定的时机下一次将多条重做日志全部写入重做日志文件,这样可以减少写磁盘的次数,从而提高数据库的性能。
重做日志缓冲区是一段循环使用的存储区,重做日志将从缓冲区的头部开始,依次写入缓冲区的各个部分。当最后一部分缓冲区被写满时,重做日志又重新被写入缓冲区的开始部分。在一定的时机下,LGWR进程将缓冲区中的重做日志写入重做日志文件,并清空这一部分重做日志所占用的存储区。例如,当重做日志缓冲区1/3的存储空间被写满时,LGWR进程便开始工作。
重做日志缓冲区的大小由初始化参数LOG_BUFFER指定,这个参数的值越大,LGWR进程写入磁盘文件的次数就越少。因此,只要计算机的内存足够大,尽可能为重做日志缓冲区分配更大的存储区,这样可以减少磁盘写操作的次数,从而提高系统的性能。