WINDOWS下的程序员出身,偶尔也写一些linux平台下小程序, 后转行数据库行业,专注于ORACLE和DB2的运维和优化。 同时也是ios移动开发者。欢迎志同道合的朋友一起研究技术。 数据库技术交流群:58308065,23618606
全部博文(599)
分类: Oracle
2011-08-22 16:15:23
ORACLE数据库闪回可以把整个数据库闪回到过去的某一个时间点。
数据库闪回类似于不完全恢复,但和不完全恢复又有很多区别。
数据库闪回可以恢复数据删除、表删除等用户错误,但是闪回却不能解决物理损坏,譬如文件删除等。
虽然ORACLE的数据库闪回不能解决物理损坏等错误,但有时候可以解决数据库坏块。
当然处理数据库坏块最方便的方法莫过于RMAN的BLOCKRECOVER命令,而且如果闪回日志中不存在相关坏块的前映像的话,
这个方法也行不通了。
有关数据库的闪回配置可以参考metalink 文档 NOTE:ID 249319.1。
以下是一个简单的利用数据库闪回修复坏块的例子:
C:\Documents and Settings\shoupeng.yan>sqlplus test/test
SQL*Plus: Release 10.2.0.1.0 - Production on 星期一 8月 22 14:13:37 2011
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> SHOW PARAMETER DB_BLOCK_SIZE
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_block_size integer 8192
SQL> CREATE TABLE T(ID INT,COL1 CHAR(2000),COL2 CHAR(2000),COL3 CHAR(2000));
表已创建。
首先创建表T,定义3个长度是2000的列,BLOC大小K是8K的,为了方便起见,这样每个块只能存放一条记录。
然后往表里插入6条记录:
SQL> INSERT INTO T VALUES(1,RPAD('1',2000,'1'),RPAD('1',2000,'1'),RPAD('1',2000,'1'));
已创建 1 行。
SQL> INSERT INTO T VALUES(2,RPAD('2',2000,'2'),RPAD('2',2000,'2'),RPAD('2',2000,'2'));
已创建 1 行。
SQL> INSERT INTO T VALUES(3,RPAD('3',2000,'3'),RPAD('3',2000,'3'),RPAD('3',2000,'3'));
已创建 1 行。
SQL> INSERT INTO T VALUES(4,RPAD('4',2000,'4'),RPAD('4',2000,'4'),RPAD('4',2000,'4'));
已创建 1 行。
SQL> INSERT INTO T VALUES(5,RPAD('5',2000,'5'),RPAD('5',2000,'5'),RPAD('5',2000,'5'));
已创建 1 行。
SQL> INSERT INTO T VALUES(6,RPAD('6',2000,'6'),RPAD('6',2000,'6'),RPAD('6',2000,'6'));
已创建 1 行。
SQL> COMMIT;
提交完成。
SQL> SELECT ID,DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) FILE#,
2 DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) BLOCK#
3 FROM T
4 ORDER BY ID;
ID FILE# BLOCK#
---------- ---------- ----------
1 7 1568
2 7 1564
3 7 1565
4 7 1566
5 7 1567
6 7 1570
已选择6行。
SQL> CONN / AS SYSDBA
已连接。
SQL> SELECT FLASHBACK_ON,LOG_MODE FROM V$DATABASE;
FLASHBACK_ON LOG_MODE
------------------ ------------
NO ARCHIVELOG
SQL> SHUTDOWN IMMEDIATE
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP MOUNT
ORACLE 例程已经启动。
Total System Global Area 1073741824 bytes
Fixed Size 1250044 bytes
Variable Size 746589444 bytes
Database Buffers 318767104 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
SQL> ALTER DATABASE FLASHBACK ON;
数据库已更改。
SQL> ALTER DATABASE OPEN;
数据库已更改。
SQL> SELECT FLASHBACK_ON,LOG_MODE FROM V$DATABASE;
FLASHBACK_ON LOG_MODE
------------------ ------------
YES ARCHIVELOG
数据库已经处于闪回状态,这样每当我们修改记录的时候,ORACLE将相关记录的BLOCK复制到闪回日志中。
准备工作已经完成。
我们修改ID=5的记录,这样ORACLE会把ID=5的记录所在的块1567的块复制到闪回日志中。
SQL> ALTER SESSION SET NLS_DATE_FORMAT='YYYY/MM/DD HH24:MI:SS';
会话已更改。
SQL> SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER,SYSDATE FROM DUAL;
GET_SYSTEM_CHANGE_NUMBER SYSDATE
------------------------ -------------------
9063211692914 2011/08/22 15:37:01
SQL> ALTER SYSTEM SWITCH LOGFILE;
系统已更改。
SQL> UPDATE T
2 SET COL1=RPAD('A',2000,'A')
3 WHERE ID=5;
已更新 1 行。
SQL> COMMIT;
提交完成。
SQL> ALTER SYSTEM SWITCH LOGFILE;
系统已更改。
SQL> SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER,SYSDATE FROM DUAL;
GET_SYSTEM_CHANGE_NUMBER SYSDATE
------------------------ -------------------
9063211692951 2011/08/22 15:38:37
用UtralEdit打开数据文件将记录5和6修改,以模拟坏块。
SQL> SELECT TO_CHAR(1567*8192,'XXXXXXXX') FROM DUAL;
TO_CHAR(1
---------
C3E000
SQL> SELECT TO_CHAR(1568*8192,'XXXXXXXX') FROM DUAL;
TO_CHAR(1
---------
C40000
根据块号的块大小可以确定记录5位于文件位置的C3E000-C40000之间。
SQL> SELECT TO_CHAR(1570*8192,'XXXXXXXX') FROM DUAL;
TO_CHAR(1
---------
C44000
SQL> SELECT TO_CHAR(1571*8192,'XXXXXXXX') FROM DUAL;
TO_CHAR(1
---------
C46000
记录6位于文件位置的C44000-C46000之间。
关闭数据库修改数据文件,修改完毕打开数据库。
SQL> SHUTDOWN IMMEDIATE
ORA-01031: 权限不足
SQL> CONN / AS SYSDBA
已连接。
SQL> SHUTDOWN IMMEDIATE
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP
ORACLE 例程已经启动。
Total System Global Area 1073741824 bytes
Fixed Size 1250044 bytes
Variable Size 738200836 bytes
Database Buffers 327155712 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
数据库已经打开。
SQL> CONN TEST/TEST
已连接。
SQL> SELECT ID FROM T;
ERROR:
ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 1567)
ORA-01110: 数据文件 7:
'C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF'
未选定行
SQL> ALTER SESSION SET EVENTS '10231 TRACE NAME CONTEXT FOREVER,LEVEL 10';
会话已更改。
SQL> SELECT ID FROM T ORDER BY ID;
ID
--------------------
1
2
3
4
设置10231事件可以让ORACLE跳过坏块,可以看到,ID=5和ID=6的记录已经跳过了。
通过DBV也可以看出块1567和1570已经是坏块:
Microsoft Windows XP [版本 5.1.2600]
(C) 版权所有 1985-2001 Microsoft Corp.
C:\Documents and Settings\shoupeng.yan>dbv file=C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF
DBVERIFY: Release 10.2.0.1.0 - Production on 星期一 8月 22 15:47:38 2011
Copyright (c) 1982, 2005, Oracle. All rights reserved.
DBVERIFY - 开始验证: FILE = C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TES
T02.DBF
页 1567 标记为损坏
Corrupt block relative dba: 0x01c0061f (file 7, block 1567)
Bad check value found during dbv:
Data in bad block:
type: 6 format: 2 rdba: 0x01c0061f
last change scn: 0x083e.3183738d seq: 0x1 flg: 0x06
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x738d0601
check value in block header: 0xf345
computed block checksum: 0xe29b
页 1570 标记为损坏
Corrupt block relative dba: 0x01c00622 (file 7, block 1570)
Bad check value found during dbv:
Data in bad block:
type: 6 format: 2 rdba: 0x01c00622
last change scn: 0x083e.318371a6 seq: 0x1 flg: 0x04
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x71a60601
check value in block header: 0x884
computed block checksum: 0x301
DBVERIFY - 验证完成
检查的页总数: 6400
处理的页总数 (数据): 3212
失败的页总数 (数据): 0
处理的页总数 (索引): 134
失败的页总数 (索引): 0
处理的页总数 (其它): 145
处理的总页数 (段) : 0
失败的总页数 (段) : 0
空的页总数: 2907
标记为损坏的总页数: 2
流入的页总数: 0
最高块 SCN : 830697894 (2110.830697894)
此时我们将数据库闪回到UPDATE语句后我们记录的那个时间点。
SQL> CONN / AS SYSDBA
已连接。
SQL> SHUTDOWN IMMEDIATE
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP MOUNT
ORACLE 例程已经启动。
Total System Global Area 1073741824 bytes
Fixed Size 1250044 bytes
Variable Size 746589444 bytes
Database Buffers 318767104 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
SQL> FLASHBACK DATABASE TO SCN 9063211692951;
闪回完成。
SQL> ALTER DATABASE OPEN READ ONLY;
数据库已更改。
SQL> SELECT ID FROM TEST.T;
ERROR:
ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 1570)
ORA-01110: 数据文件 7:
'C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF'
未选定行
SQL> ALTER SESSION SET EVENTS '10231 TRACE NAME CONTEXT FOREVER,LEVEL 10';
会话已更改。
SQL> SELECT ID FROM TEST.T;
ID
--------------------
2
3
4
5
1
可以看到块1567已经修复了,但是块1570没有被修复,这是由于这个BLOCK在闪回日志中不存在,无法覆盖掉原来的坏块。
从DBV的输出中也可以看出块1567已经修复:
C:\Documents and Settings\shoupeng.yan>dbv file=C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF
DBVERIFY: Release 10.2.0.1.0 - Production on 星期一 8月 22 15:57:58 2011
Copyright (c) 1982, 2005, Oracle. All rights reserved.
DBVERIFY - 开始验证: FILE = C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TES
T02.DBF
页 1570 标记为损坏
Corrupt block relative dba: 0x01c00622 (file 7, block 1570)
Bad check value found during dbv:
Data in bad block:
type: 6 format: 2 rdba: 0x01c00622
last change scn: 0x083e.318371a6 seq: 0x1 flg: 0x04
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x71a60601
check value in block header: 0x884
computed block checksum: 0x301
DBVERIFY - 验证完成
检查的页总数: 6400
处理的页总数 (数据): 3213
失败的页总数 (数据): 0
处理的页总数 (索引): 134
失败的页总数 (索引): 0
处理的页总数 (其它): 145
处理的总页数 (段) : 0
失败的总页数 (段) : 0
空的页总数: 2907
标记为损坏的总页数: 1
流入的页总数: 0
最高块 SCN : 830698378 (2110.830698378)
剩下的工作是将数据库恢复到最新状态。
SQL> SHUTDOWN IMMEDIATE;
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP MOUNT
ORACLE 例程已经启动。
Total System Global Area 1073741824 bytes
Fixed Size 1250044 bytes
Variable Size 746589444 bytes
Database Buffers 318767104 bytes
Redo Buffers 7135232 bytes
数据库装载完毕。
SQL> RECOVER DATABASE;
完成介质恢复。
SQL> ALTER DATABASE OPEN;
数据库已更改。
SQL> SELECT ID FROM TEST.T;
ERROR:
ORA-01578: ORACLE 数据块损坏 (文件号 7, 块号 1570)
ORA-01110: 数据文件 7:
'C:\U01\ORACLE\PRODUCT\10.2.0\ORADATA\YANSP\YANSP\TEST02.DBF'
未选定行
当然数据块1570还是坏块。
这个只能利用备份来修复了。
SQL> host rman target /
恢复管理器: Release 10.2.0.1.0 - Production on 星期一 8月 22 16:11:14 2011
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到目标数据库: YANSP (DBID=969718535)
RMAN> BLOCKRECOVER DATAFILE 7 BLOCK 1570;
启动 blockrecover 于 22-8月 -11
使用目标数据库控制文件替代恢复目录
分配的通道: ORA_DISK_1
通道 ORA_DISK_1: sid=498 devtype=DISK
通道 ORA_DISK_1: 正在恢复块
通道 ORA_DISK_1: 正在指定要从备份集恢复的块
正在恢复数据文件 00007 的块
通道 ORA_DISK_1: 正在读取备份段 C:\ORACLE_BACKUP\INCREMENT_0JMDMU8R_1_1.BAK
通道 ORA_DISK_1: 已从备份段 1 恢复块
段句柄 = C:\ORACLE_BACKUP\INCREMENT_0JMDMU8R_1_1.BAK 标记 = TAG20110531T1014
通道 ORA_DISK_1: 块恢复完成, 用时: 00:00:03
正在开始介质的恢复
介质恢复完成, 用时: 00:00:15
完成 blockrecover 于 22-8月 -11
RMAN> EXIT
恢复管理器完成。
SQL> SELECT ID FROM TEST.T;
ID
--------------------
2
3
4
5
1
6
已选择6行。