如是我闻

没有什么能够阻挡,我对自由的向往

Oracle数据库归档日志详解

04-28, 2019 Oracle

前言

Oracle 数据库在数据出错时可以使用 重做日志 (Redo Log)进行恢复,重做日志分为两部分:

  • 在线重做日志文件 (Online Redo Log Files)
  • 归档日志文件 (Archive Redo Log Files)

这里主要说一下归档日志 (Archive Log),在线重做日志大小毕竟是有限的,当都写满了的时候,就面临着2个选择,第一个就是把以前在线重做日志从头擦除开始继续写,第二种就是把以前的在线重做日志先进行备份,然后对被备份的日志擦除开始写新的在线 Redo Log,数据库如果采用这种生成归档日志的模式的话,就是归档日志模式 (ARCHIVELOG),反之如果不生成归档日志,就是非归档日志模式 (NOARCHIVELOG)。

Oracle 数据库默认采用的是非归档模式,假如说一共有三个重做日志组,当三个日志组全部写满之后将从第一个日志组开始循环记录,并且第一个日志组中的内容将被彻底覆盖,这样,如果数据库崩溃了,就没办法恢复很早之前的数据了。而使用归档模式后,这样写入日志循环的时候,会先把日志组中的数据写入到归档日志中,然后才会被覆盖,这样恢复问题就解决了,下面是一些常用的操作。

改变数据库归档模式

首先使用 oracle 用户登入数据库服务器,然后进入 sqlplus 环境:

$ sqlplus /nolog

使用管理员连接到数据库:

SQL> CONN /AS SYSDBA;

查看当前归档模式,显示为非归档模式:

SQL> SELECT LOG_MODE FROM V$DATABASE;     

LOG_MODE
------------
NOARCHIVELOG

改变归档日志模式前要先关闭数据库:

SQL> SHUTDOWN IMMEDIATE;

数据库以 MOUNT 方式启动:

SQL> STARTUP MOUNT;

启用归档模式:

SQL> ALTER DATABASE ARCHIVELOG;

关闭归档模式:

SQL> ALTER DATABASE NOARCHIVELOG;

最后打开数据库:

SQL> ALTER DATABASE OPEN;

查看归档日志信息:

SQL> ARCHIVE LOG LIST;

Database log mode	       Archive Mode
Automatic archival	       Enabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     330
Next log sequence to archive   332
Current log sequence	       332

归档路径管理

首先查看默认的归档日志路径:

SQL> SHOW PARAMETER DB_RECOVERY_FILE_DEST;

NAME				     TYPE	 VALUE
------------------------------------ ----------- ------------------------------
db_recovery_file_dest		     string	 /data/oracle/flash_recovery_area
db_recovery_file_dest_size	     big integer 4977M

Oracle11g 版本,Oracle 默认的日志归档路径为闪回恢复区 ($ORACLE_BASE/flash_recovery_area)。对于这个路径,Oracle 有一个限制,就是默认只有 4G 的空间,而且不只是归档日志的默认路径,也是备份文件和闪回日志的默认地址,所以空间很容易不足,可以通过以下几个方式修改。

  • 增大闪回空间大小:
SQL> ALTER SYSTEM SET DB_RECOVERY_FILE_DEST_SIZE=8G SCOPE=SPFILE;
  • 修改归档日志存储路径:
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_1='LOCATION=/DATA/ORACLE/ARCHIVE_LOG' SCOPE=SPFILE;

修改归档日志格式:

SQL> ALTER SYSTEM SET LOG_ARCHIVE_FORMAT='ARCH_%D_%T_%R_%S.ARC' SCOPE=SPFILE;

归档日志清理

随着时间的推移,归档日志可能会占满磁盘空间,这将导致无法连接到数据库,所以需要定期的清理一部分归档日志。那么我们就直接物理删除一些归档日志呗,可是别高兴的太早,在 Oralce 的 Control File 中仍然记录着这些 archivelog 文件的相关信息,当我们手工清除这些文件后,这些记录并没有被我们从 Control File 中清除掉,也就是 Oracle 并不知道这些文件已经不存在了。正确的方法是利用 Oracle 提供的 RMAN 工具进行清理。

正确删除归档日志的过程

使用 oracle 用户登入数据库服务器,然后进入 rman 环境:

$ rman

rman 连接到本地数据库后就可以对归档日志进行清理了:

# 连接到本地数据库
RMAN> connect target /
# 核对控制文件和实际物理文件
RMAN> crosscheck archivelog all;
# 删除失效的归档日志文件,同步控制文件和物理文件信息。
RMAN> delete expired archivelog all;
# 删除 7 天前的归档日志
RMAN> delete archivelog all completed before 'sysdate-7';

定时清理归档日志

每次手工清理比较麻烦,而且也容易忘记,可以写一个自动清理脚本,然后利用定时任务定时进行清理。

首先使用 oracle 用户登入到数据库服务器,然后在 /home/oracle/auto_del_arc/ 目录下新建一个 del_arc.sh 自动清理脚本:

# 在oracle用户目录下新建一个存放脚本和日志的文件夹
$ mkdir /home/oracle/auto_del_arc
# 新建脚本文件
$ touch /home/oracle/auto_del_arc/del_arc.sh

然后将以下内容复制到 del_arc.sh 后保存退出:

#!/bin/bash
echo "----------------------------------------`date`---------------------------------------"
if [ -f ~/.bash_profile ]; then
. ~/.bash_profile
fi

export Today=`date +%Y%m%d`

$ORACLE_HOME/bin/rman target / log=~/auto_del_arc/${Today}.log <<EOF
run{
crosscheck archivelog all;
delete noprompt expired archivelog all;
delete noprompt archivelog all completed before 'sysdate - 7';
}
exit;
EOF
echo -e "\n"
echo "------------------------------------ FINISHED ------------------------------------"

赋予清理脚本可执行权限:

$ chmod a+x /home/oracle/auto_del_arc/del_arc.sh

最后使用 oracle 用户把清理脚本添加到定时任务:

# 编辑定时任务
$ crontab -e

在文件中添加如下行,代表每天凌晨2点执行清理脚本:

00 02 * * * /home/oracle/auto_del_arc/del_arc.sh