SQL> show parameter buffer;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
buffer_pool_keep string
buffer_pool_recycle string
db_block_buffers integer 0
log_buffer integer 5246976
(在Oracle数据库当中,执行数据修改之后,并不是立刻写入数据文件,而是首先生成重做信息,并写入到SGA当中一块叫log buffer的固定区域,log buffer的空间并不是无限大,实际上非常小,一般3M-5M左右,log buffer有一定的触发条件,当触发条件满足时,会有相应的进程将log buffer里面的数据写入到一个特点类型的文件,这个文件就是redo log file)
对于Oracle数据库来说,再做DDL或者DML操作的时候,会在buffer cache里面去修改一个数据块,当这个数据块被修改的时候,这个数据块和数据文件里面的数据块不一致了,所以将其称之为脏块。
脏块会放到一个队列里面将其排队,满足一定条件的时候会去通知dbwr进程将buffer cache里面的脏块写入到数据文件里面。
如果数据库突然掉电了,导致数据库重启了,会导致放在buffer cache里面的脏块丢失,这样会导致数据丢失,oracle为了保证数据安全有一个先记后写的机制,当修改脏块,脏块发生变化之后,将数据块变化后的信息写入到redo日志里面,通过server进程将redo日志写到log buffer里来生成redo日志条目,redo日志条目记录了数据块的变化,有了数据块的变化在丢失数据的时候,就可以通过这些变化后的数据进行redo重做来实现数据的恢复。
在log buffer里面的日志条目在提交的时候会通过lgwr进程将其写入到redo日志文件里,或者每过三秒钟或者写脏数据之前等,都会将redo log buffer里面的数据条目写入到日志文件里面。
对于redo日志文件是以日志组的形式来管理的,对于oracle来说至少有两组日志,当将其中一组日志写满之后会发生一个切换,切换到下一组日志。
当只有两个日志组,日志组1写满之后切换到日志组2,组2写满之后再切换到组1,切换到组1之后,如果组1上面的历史日志如果直接覆盖,那么就称为这是一个非归档的数据库。
如果是归档的数据库,那么在日志组1在发生切换的时候将其历史日志备份到一个地方,这个地方就称为归档,归档的数据库将其历史的日志进行了保存,那么在恢复的时候就可以通过备份加上归档来对数据库进行恢复。
如果事务的并发量很大,组2的日志很快就被写满了会切换到组1,这个时候对于组1的归档可能还没有完成,数据库在归档没有完成的时候日志组是切换不过来的,数据库不允许切换,日志组不能切换就没办法写出,这个时候log buffer可能就会被写满了,事务就没办法提交了,这个时候数据库就被hang住了,这个时候就需要添加新的日志组了。
下图就是上面内容的描述:
添加日志文件组
SQL> select group#,status,type,member from v$logfile;
GROUP# STATUS TYPE MEMBER
---------- ------- ------- --------------------------------------------------
1 ONLINE /u01/app/oracle/oradata/oradb/redo01a.log
2 ONLINE /u01/app/oracle/oradata/oradb/redo02.log
3 ONLINE /u01/app/oracle/oradata/oradb/redo03.log
(type 列有两个值,standby表示该日志文件为standby库专用,即为standby redo logs,online则表示该日志文件为普通·联机重做日志文件)
SQL> alter database add logfile group 4 '/u01/app/oracle/oradata/oradb/redo04a.log' size 50m; --添加一个日志文件组
Database altered.
SQL> select group#,member from v$logfile;
GROUP# MEMBER
---------- --------------------------------------------------
1 /u01/app/oracle/oradata/oradb/redo01.log
2 /u01/app/oracle/oradata/oradb/redo02.log
3 /u01/app/oracle/oradata/oradb/redo03.log
4 /u01/app/oracle/oradata/oradb/redo04a.log
SQL> select GROUP#,SEQUENCE#,STATUS,ARCHIVED from v$log;
GROUP# SEQUENCE# STATUS
1 1 INACTIVE NO
2 2 CURRENT NO
3 0 UNUSED YES
4 0 UNUSED YES
在添加日志组的时候,最好保证每个日志组的成员个数和大小一样。
SQL> alter database add logfile group 1 ('/u01/app/oracle/oradata/oradb/redo01a.log','/u02/app/oracle/oradata/oradb/redo02b.log') size 50m;
SQL> select group#,member from v$logfile;
GROUP# MEMBER
---------- --------------------------------------------------
1 /u01/app/oracle/oradata/oradb/redo01a.log
2 /u01/app/oracle/oradata/oradb/redo02.log
3 /u01/app/oracle/oradata/oradb/redo03.log
4 /u01/app/oracle/oradata/oradb/redo04a.log
1 /u02/app/oracle/oradata/oradb/redo02b.log
(Oracle建议每组重做日志至少有一份冗余,即为每个重做日志文件保持多份镜像,这样一旦磁盘出现损坏,或者误操作丢失了某个重做日志文件,只要该组至少有一个重做日志文件正常就能够保证数据不会丢失)
添加日志文件
SQL> select group#,member from v$logfile;
GROUP# MEMBER
---------- --------------------------------------------------
1 /u01/app/oracle/oradata/oradb/redo01a.log
2 /u01/app/oracle/oradata/oradb/redo02.log
3 /u01/app/oracle/oradata/oradb/redo03.log
4 /u01/app/oracle/oradata/oradb/redo04a.log
SQL> alter database add logfile member '/u01/app/oracle/oradata/oradb/redo04b.log' to group 4;
Database altered.
(在添加重做日志文件不能指定大小,因为每个重做日志文件组中的文件都是相互冗余的,因此文件大小是一致的)
SQL> select group#,member from v$logfile;
GROUP# MEMBER
---------- --------------------------------------------------
1 /u01/app/oracle/oradata/oradb/redo01a.log
2 /u01/app/oracle/oradata/oradb/redo02.log
3 /u01/app/oracle/oradata/oradb/redo03.log
4 /u01/app/oracle/oradata/oradb/redo04a.log
4 /u01/app/oracle/oradata/oradb/redo04b.log
删除日志文件组和日志文件
对于删除日志组,什么样日志组是可以删除的呢?每一个日志组都有一个状态,在删除日志组的时候一定要先判断要删除的日志组的状态。
Inactive:表示当前这组日志记录的脏块被写入到data file了,即已经写入到磁盘了,如果是归档的状态,表示该日志也已经归档。这个日志组是可以删除的。
Active:日志组虽然当前未被使用,不过该文件中的内容尚未归档,或者对应的脏数据未被全部写入磁盘,一旦需要实例恢复,必须借助该文件中保存的内容。
Current:代表当前日志组,修改数据块生成的日志都在buffer cache里面,还未被写出,这组日志也是不允许被删除的。
要删除日志组必须保证日志组的状态必须是inactive的。
SQL> alter database drop logfile group 1;
Database altered.
SQL> select GROUP#,SEQUENCE#,STATUS from v$log;
GROUP# SEQUENCE# STATUS
---------- ---------- ----------------
2 2 INACTIVE
3 3 CURRENT
4 0 UNUSED
如果想将某个日志组删除就要不断切换日志,将其日志组变为inactive状态。然后删除该日志组(alter system switch logfile)。
SQL> alter database drop logfile member '/u02/app/oracle/oradata/oradb/redo02b.log';
alter database drop logfile member '/u02/app/oracle/oradata/oradb/redo02b.log'
*
ERROR at line 1:
ORA-01609: log 1 is the current log for thread 1 - cannot drop members
同理删除日志组中的日志文件也要保证日志组是inactive的状态
SQL> alter system switch logfile;
System altered.
SQL> select group#,members,status from v$log;
GROUP# MEMBERS STATUS
---------- ---------- ----------------
1 2 INACTIVE
2 1 CURRENT
3 1 INACTIVE
4 1 ACTIVE
SQL> alter database drop logfile member '/u02/app/oracle/oradata/oradb/redo02b.log';
Database altered.