redo是数据库的安全机制,也是保障数据库稳定运行的重要手段。
数据库的insert、delete、update等DML操作,以及创建表、索引、表空间等DDL操作最终都会转换为物理文件的改变。redo日志记录了数据库发生的所有物理变化。当服务器发生断电或其他故障,导致系统崩溃,数据库实例意外中止时,内存中没有写入数据文件的数据就会丢失。这时只要redo日志写入了联机日志文件,数据库实例重启时,就可以根据联机日志中的redo日志将数据库恢复到系统崩溃前的状态。
为了减少磁盘I/O,redo日志产生后并不会被立即写入联机日志文件,而是先存放在日志缓冲区内,然后刷新到磁盘上的日志文件中。redo日志的刷新机制与数据缓冲区的检查点不同,每个事务的提交(commit)都会触发日志缓冲区的刷新,因此redo日志的刷新频率远高于数据文件的写入。
redo日志文件中日志记录增加到参数CKPT_RLOG_SIZE设定的大小时,就会触发检查点,将脏数据页写入数据文件。redo日志文件写满后,会切换到下一个日志文件。
系统视图V$RLOGFILE可以查询到全部联机日志文件的文件id、物理路径、文件大小等信息。
系统视图V$RLOG可以查询到redo日志刷新的信息,其中CUR_FILE字段显示当前使用的日志文件id。
redo的设置对数据库的运行性能影响非常大,但在创建数据库时很多DBA往往只关注内存参数的设置,而忽视了redo的设置。
达梦数据库的联机日志文件有多个,一个日志文件写满后,随即切换到另一个。数据库运行过程中产生的待写入日志首先写入redo日志包RLOG_PKG,当日志刷盘时一起写入联机日志文件中。在联机日志文件中,可以覆盖写入redo日志的文件长度为可用日志空间,系统故障重启时进行实例恢复需要的redo日志称为有效日志。为了保证数据库实例的安全,有效日志是不能被覆盖的(相当于Oracle数据库的redo文件处于active状态),其LSN取值范围是(CKPT_LSN,FILE_LSN]。当所有的联机日志文件都不能被使用时,就意味着redo日志空间写满了。
达梦数据库的日志空间一旦写满,运行日志会出现提示:“Redo log try flush over space”“日志环被冲破”。此时的数据库无法正常运行,需要重启实例才能恢复。
针对联机日志文件空间写满的情况,达梦提供了两个控制参数。
(1)RLOG_CHECK_SPACE:是否检查日志空间,取值范围为0、1。1表示日志刷盘时,检查日志空间是否溢出,是则生成错误日志并强制退出,以确保数据文件不被破坏。0表示不检查日志空间是否溢出。默认值为1。
(2)RLOG_SAFE_SPACE:安全的可用日志空间大小,有效值范围为0~1024,默认值为128(MB)。当系统的可用日志空间小于这个值时,会触发检查点刷新数据缓冲区中的脏数据页,释放相应的日志空间。
达梦数据库默认安装后会创建两个联机日志文件,默认大小为256MB,全部联机日志容量只有512MB,这个设置显然是有些保守。增大联机日志空间的方法有两个:增大联机日志文件大小,增加联机日志文件数量。在同样大小的日志空间的情况下,日志文件数量多一些效果会更好。联机日志文件至少应该有三个,日志空间至少为4GB。
除了增加联机日志空间容量,及时触发检查点,释放日志空间也是非常有效的手段。数据变更非常频繁的系统可以根据实际业务情况修改以下的检查点参数。
(1)CKPT_INTERVAL,检查点间隔时间,默认值为180秒。
(2)CKPT_FLUSH_RATE,检查点刷新比例,默认值为5(%)。
(3)CKPT_FLUSH_PAGES,检查点最小刷新页数,默认值为1000。
(4)CKPT_WAIT_PAGES,检查点最大刷新页数,默认值为1024。
(5)CKPT_DIRTY_PAGES,触发检查点的脏数据页数量,默认值为0(不启用)。
(6)CKPT_RLOG_SIZE,触发检查点的日志文件增加量,默认值为128(MB)。
(7)RLOG_SAFE_SPACE,可用日志空间安全值,默认值为128(MB)。
检查点参数的设置对系统性能影响很大,修改要慎重。
达梦数据库的redo日志文件与Oracle数据库的有所不同,只能增加不能删除,只能增大不能减小。
增加日志的操作命令如下:
SQL> alter database add logfile '/dm/data/DAMENG/DAMENG05.log' size 32;
注意 redo文件至少要包含4096页,如果页面大小为8KB,则文件最小为32MB。
增大日志的操作:
SQL> alter database resize logfile '/dm/data/DAMENG/DAMENG05.log' to 64;
Oracle数据库可以手动切换日志:
SQL> alter system switch logfie;
但达梦数据库的联机日志文件只能写满后切换,Oracle数据库的切换语句在达梦数据库也可以执行,但切换的是归档日志。
也可以在管理工具manager中添加、修改日志文件。
右击数据库连接,在弹出的快捷菜单中选择“管理服务器”选项,如图3-1所示。
进入图3-2所示的“管理服务器”界面,选择“日志文件”选项。在打开的页面中可以直接修改文件大小,也可以单击“添加”按钮,增加日志文件。
图3-1
图3-2
commit(提交)操作会将日志缓冲区中的redo信息刷新到联机日志文件中,从而保证事务数据的安全。
及时提交事务可以保证数据安全,但频繁地刷新日志缓冲区产生的大量磁盘I/O对数据库性能的影响也非常大。示例如下:
由上述操作可知,向表t1插入100万条数据,每次插入一条数据后进行一次提交操作,执行时间为1分52秒。
如果在插入全部数据完成后再提交,看看效率如何。
可以看到,100万条数据全部插入完成后再执行提交,只用了不到6秒,执行效率非常高。
两次操作产生这么大差距的原因在于第二次操作发挥了日志缓冲区的缓冲作用,极大地减少了磁盘I/O。
Oracle数据库通过将表设置为nologging模式,使用append(直接路径加载,hwm高水位线上插入)的方式可以减少redo日志的产生,提高大数据量插入的速度。
达梦数据库也提供了这样的功能,使用方法与Oracle数据库一致。如果是非归档方式下,可以直接使用append,无须将表设置为nologging模式。
注意,append方式只对批量插入方式有效,常规的单条记录插入无效。此外,append方式插入的数据因为缺少redo信息,在进行备份恢复时会无法恢复数据。因此,批量插入完成后要视情况及时进行数据备份。
归档模式是数据库的一种运行模式。达梦数据库在归档模式下会将redo日志写入联机日志文件后,再写入归档日志文件。
由于日志归档比写入联机日志文件要延迟很多,因此达梦数据库的日志缓冲区的RLOG_BUF_SIZE和日志缓冲池RLOG_POOL_SIZE要比Oracle数据库的日志缓冲区log_buffer大很多,就是在等待归档的完成。
查询数据库是否处于归档模式的命令:
SQL> select arch_mode from v$database;
也可以在manager管理工具中,右击数据库连接,如图3-3所示,在弹出的快捷菜单中选择“管理服务器”选项。
如图3-4所示,在“系统概览”页面查看“归档模式”。
图3-3
图3-4
开启归档的方法很简单,如图3-5所示,在“管理服务器”页面选择“系统管理”选项,然后选中“配置”单选按钮。
图3-5
单击“转换”按钮,进入配置状态。选择“归档配置”选项,进入配置页面,如图3-6所示。选中“归档”单选按钮,配置归档路径、归档文件大小、归档空间限制等参数,单击“确定”按钮完成操作。
图3-6
回到“系统管理”页面,选中“打开”单选按钮,单击“转换”按钮,如图3-7所示。
图3-7
归档模式设置完成后,可以在系统视图V$DATABASE中查询归档模式字段(ARCH_MODE),如图3-8所示。
图3-8
也可以直接编辑配置文件dm.ini,修改参数ARCH_INI=1。
然后在配置文件dm.ini的路径下手动创建dmarch.ini文件,输入参数值。例如:(1)ARCH_TYPE = LOCAL #本地归档。
(2)ARCH_DEST = E:/dmdbms/dmarch #归档路径。
(3)ARCH_FILE_SIZE = 128 #归档日志文件大小(MB)。
(4)ARCH_SPACE_LIMIT = 1024 #归档空间大小限制(MB)。
重启数据库实例后,数据库即进入归档模式运行。
还可以像Oracle数据库一样,使用disql工具,执行归档命令。
(1)修改数据库状态为MOUNT。
SQL> ALTER DATABASE MOUNT;
(2)配置本地归档参数。
SQL> ALTER DATABASE ADD ARCHIVELOG 'DEST = E:/dmdbms/dmarch, TYPE = local, FILE_SIZE = 128, SPACE_LIMIT = 1024';
(3)开启归档模式。
SQL> ALTER DATABASE ARCHIVELOG;
(4)打开数据库。
SQL> ALTER DATABASE OPEN;
正常情况下,归档日志文件写满后系统自动切换,生成新的归档文件。实例重启时会发生归档切换。也可以手动执行命令切换,命令有三个。
SQL> alter system switch logfile; SQL> alter system archive log current; SQL> alter database archive log current;
关于归档日志文件大小的设置,建议不大于联机日志文件,最好是联机日志文件大小的一半,切换间隔时间太长不利于归档日志备份。
redo日志记录数据库的变更操作,除了用于数据库实例恢复以外,也可以用来进行日志挖掘,从中获取有用的信息。
Oracle数据库提供了logminer工具对redo日志进行挖掘分析。达梦数据库也提供了DBMS_LOGMNR包,可以方便对数据库归档日志进行挖掘,重构DDL、DML和DCL等操作,从而达到审计及跟踪数据库操作的目的。特殊情况下,还可以用来恢复被删除、修改的数据。
与Oracle数据库不同,达梦数据库的DBMS_LOGMNR只能对归档日志进行挖掘。所以,进行日志挖掘要先将数据库设置为归档模式。
redo日志记录了数据库的物理变化,信息非常精简,很多不必要的信息被省略了,这样挖掘出来的信息可读性较差。Oracle数据库采取的措施是补充日志,增加redo记录的内容。
达梦数据库的日志挖掘的思路与Oracle数据库一致,参数RLOG_APPEND_LOGIC用来控制在日志中记录逻辑操作,增加redo记录的信息。
RLOG_APPEND_LOGIC参数设置说明如下:
0: 不启用。
1: 如果有主键列,记录update和delete操作时只包含主键列信息,若没有主键列则包含所有列信息。
2: 不论是否有主键列,记录update和delete操作时都包含所有列的信息。
3: 记录update时包含更新列的信息以及rowid,记录delete时只有rowid。
从记录信息来看,参数3记录的信息最少,2最多。
日志挖掘过程步骤如下。
(1)添加归档日志文件。
SQL> dbms_logmnr.add_logfile('dm/data/DAMENG/arch/ARCHIVE_LOCAL1_0x74387489_ EP0_2022-10-10_20-35-41.log');
可以添加多个日志文件,从系统视图V$LOGMNR_LOGS可以查看当前会话添加的日志文件信息。
(2)开始日志挖掘。
SQL> dbms_logmnr.start_logmnr(options =>2130);
OPTIONS参数包括如表3-2所示的可选模式,各模式可以通过相加进行组合。例如,组合全部模式,则取值2+16+64+2048=2130,那么OPTIONS的值就是2130。
表3-2
如果只想挖掘部分时间段内的日志信息,可以增加参数starttime、endtime,例如:
SQL> dbms_logmnr.start_logmnr(options=>2130,starttime= >'2022-10-9 18:00', endtime=>'2022-10-9 22');
(3)查看日志挖掘结果。
当前会话通过系统视图V$LOGMNR_CONTENTS查看日志挖掘结果。其中,scn、timestamp两个字段记录了操作的scn、时间,user字段记录了执行操作的用户,seg_owner、table_name两个字段记录了表所属的模式、表名,sql_redo记录了操作的SQL语句,sql_undo目前还未实现,实现后会记录反操作的SQL语句。
V$LOGMNR_CONTENTS只能供当前会话查询,会话结束内容消失。如果想保存挖掘结果可以将视图内容转存到物理表中:
SQL> create table logmnr_contents as select * from v$logmnr_contents;
(4)关闭日志挖掘。
SQL> DBMS_LOGMNR.END_LOGMNR();
不同数据库的redo机制差别很大,也体现出不同的技术风格。
SQL Server的日志文件就一组,虽然也可以增加多个,但逻辑上还是相当于一个文件。而且,SQL Server的日志文件还担负着undo的功能。
在简单恢复模式下,SQL Server的日志文件在事务结束后会自动将该事务产生的日志信息“截断”,占用的空间可以重复使用。因此日志文件不需要很大,一般也不会增长。
在完全恢复模式下,为了保证数据库可以恢复到备份期间的任意时刻,SQL Server的日志文件中的日志信息会一直保存,直到日志文件做了备份才会重新利用原来的存储空间(仅做数据文件备份不行)。因此,日志文件比简单模式下要大很多。而且SQL Server的数据库备份只是备份数据文件,这一点要注意。为了防止日志文件增长过大,一定要定期备份日志文件。
SQL Server还有一种大容量日志恢复模式。这种模式在大量数据导入(bulk insert)时会通过使用最小方式记录操作,减少日志空间使用量,可以大幅提升数据导入的速度,并可以防止日志文件快速增长。bulk操作结束后恢复到完全恢复模式。
MySQL 8.0的ib_logf i le和binlog都是MySQL的日志,但这两者的作用是不一样的。
ib_logf i le记录着数据库的物理变化,默认是两个,重复切换使用,跟达梦数据库的redo的作用是一样的,主要是用来做实例恢复。参数innodb_log_files_in_group控制事务日志文件数量。参数innodb_log_file_size控制事务日志ib_logfile的大小,范围为5MB~4GB。所有事务日志大小加起来不能超过4GB。
binlog是MySQL的二进制日志,跟达梦数据库的归档日志非常相似。
binlog默认大小为1GB(最大也是1GB),不会重用,写满了(或重启)会自动再创建一个新的文件,是一个实时写入的归档日志文件,内容为数据库的逻辑变化(SQL语句)记录。
可以通过命令来查看binlog中记录的内容:
mysql> show binlog events in 'binlog.000002'\G;
也可以生成文件:
mysqlbinlog --start-datetime ="2022-03-16 09:20:00" --stop-datetime = "2022-03-16 09:34:00" binlog.000002 > /bak/rec.sql
Oracle数据库的redo日志文件有四种状态。
(1)UNUSED状态是从未被使用的日志组,新添加或重新创建的日志组也是这个状态。
(2)CURRENT状态为LGWR进程正把redo log buffer的日志写入的日志组,也就是正在使用的redo文件。
(3)ACTIVE为刚刚完成日志切换后的状态,此时该日志组中记录的发生改变的数据块还没有完全从DB buffer cache写入到数据文件中,因此该日志组还不能被覆盖,等到相应的脏数据页完全写入数据文件后,才能变为INACTIVE状态。所以如果此刻发生数据库崩溃(crash),该日志组是实例恢复必需的日志组。
(4)INACTIVE状态表示日志组中记录的发生改变的数据块已经全部写入到数据文件中,可以被覆盖。
redo日志组切换会触发增量检查点(check point),督促DBWR进程将DB buffer cache中发生变化的数据块写入数据文件中。
Oracle数据库生成的redo日志信息在写入redo日志文件之前存放在log_buffer(日志缓冲区)中,由LGWR进程负责写入日志文件。
redo文件过小会导致日志文件很快被写满,发生频繁切换。而日志文件切换会触发增量检查点和日志归档,导致磁盘I/O增加,从而影响数据库性能。严重时alert文件中会出现check point not complete(检查点未完成)的警告信息,在数据库中体现为等待事件log file switch(check point incomplete)。此时所有的非当前日志文件都处于active状态(不能被覆盖),导致日志无法切换,log_buffer中的日志记录无法写入日志文件中,此时数据库会处于停顿(suspend)状态,等待检查点完成。当切换日志文件转为inactive状态,日志文件切换完成后数据库才能恢复正常运行。
Oracle数据库早期版本中redo日志文件默认大小为50MB,10g版本增加到100MB,但到了11g又降到了50MB,19C版的redo日志文件默认安装的大小是200MB。看来Oracle数据库对redo文件大小的设置也一直很纠结。