数据库日志
DB2 数据库支持两种不同的日志模式:循环(Circular)和归档(Archival)。当新数据库创建时,系统默认的日志模式为循环。如果业务需求要求更高级的功能,您可以将日志模式从循环修改为归档。
DB2 事务日志摘要
事务是逻辑工作单元。每一个事务在事务日记文件中都存储有相应的日志记录。每个事务都有一个相应的 Redo Log 条目。Redo Log 条目将写入当前的活动日志文件。当活动日志文件变满时,它将被标记为 unavailable。此时,DB2 将接着此活动日志文件另外创建一个日志文件,并继续在其中写入日志条目。当前活动日志文件变满时,DB2 将重复这一循环过程。当事务完成后(发起 COMMIT 或 ROLLBACK 语句),相应的日志条目将被释放,因为不再需要将它们用于恢复数据库。
DB2 将一直尝试将日志条目写入主要日志文件集,也就是数据库活动时间自动分配的日志文件。如果某个事务将所有主要日志文件消耗怠尽(所有主要日志文件都被标记为 unavailable),则数据库管理员将分配一个次要日志文件。当这个文件变满时,数据库管理员将再次检查主要日志文件的状态是否为 unavailable。如果是,则再分配一个次要日志文件并继续在其中写入条目。该过程将不断重复,直到所有次要日志文件都分配并写满。如果没有主要日志文件可供写入 Redo 条目,并且已经分配最大数量的次要日志文件,则应用程序将收到以下错误消息:
SQL0964C The transaction log for the database is full.
希望您曾经遇到过这种错误。但是,如果遇到此错误,则应该根据需要增加主要和次要日志文件(或者它们的大小)的数量。在理想情况下,主要日志文件的数量或大小应该足够保存最大的事务。分配次要日志文件相当消耗资源,因为它将在运行时执行。因此,我们应该将需要在高峰工作负荷期间分配的次要日志文件数量降到最低。要更新主要或次要日志文件的数量,可以发起以下命令:
UPDATE DB CFG FOR db_name USING LOGPRIMARY value
UPDATE DB CFG FOR db_name USING LOGSECOND value
注意:如果出现此问题,则应该分析造成整个日志文件空间变满的原因是什么。它可能是由失控查询或用户错误造成的,因此增加日志文件的数量或大小只能在表面上解决问题。比如说,假设某个用户发起了一个 DELETE FROM tab1 语句,且 TAB1 是一个相当大的表。虽然这一语句看上去没什么问题,每行生成一条删除日记记录,但是如果未经过配置处理它可以轻易地将日志空间填满。
循环日志
当循环日志生效时,事务数据将通过循环的方式写入主要日志文件。当存储于某个日志文件中的所有记录都不再需要用于恢复时,该日志文件将被重用,并且可以在以后再次成为活动日志文件。这意味着在循环日志模式中,日志文件的内容最终将被新日志条目重写。由于日志文件的内容被重写覆盖了,因此我们只能将数据库恢复到最后一次完整的数据库备份。不能使用循环日志执行时间点(point-in-time)恢复。
归档日志
在归档日志模式中,redo log 条目将写入主要日志文件。但是,与循环日志不同,这些日志文件永远都不可重用。当存储于某个日志文件中的所有记录都不再需要用于恢复时,该日志文件将被标记为非活动 而不是可重用。这意味着它的内容永远都不会被覆盖。当第一个主要日志文件变满时,系统将分配一个新的日志文件,这样主要日志文件的配置数量(LOGPRIMARY 数据库参数)将一直可用。
与单个事务相关的所有条目必须在活动日志空间中保持一致。如果长时间运行的事务所需要的日志空间大于主要日志文件可以提供的空间,则可能会分配并使用次要日志文件。在归档日志模式中,通过结合使用数据库备份映像和日志文件,我们可以将数据库恢复到具体的时间点。有关此流程的详细描述请参见下文。
如何修改日志模式
创建新的 DB2 数据库时,默认的日志模式为循环日志 。如果希望将日志模式从循环修改为归档,可以执行以下步骤:
在磁盘上创建一个文件夹(比如说 e:db_namearchive),磁盘上必须有足够的空间存储归档日志文件。保证归档文件目标文件夹与活动日志文件目标文件夹分开。
终止与数据库的连接:
TERMINATE
更新归档日志文件目标文件夹(为归档日志文件指定路径可以将归档日志模式打开)。
UPDATE DB CFG FOR db_name USING LOGARCHMETH1 "Disk:e:db_namearchive"
重新连接到数据库:
CONNECT TO db_name
连接失败并显示以下错误消息:
SQL1116N A connection to or activation of database db_name cannot be made because of backup pending: SQLSTATE=57019
出现错误消息的原因是,日志模式已经从循环更改为归档,并且需要执行完全数据库备份。数据库处于循环日志模式时执行的备份并不充分,因此当切换模式后需要执行新备份。
使用以下命令执行完全数据库备份:
BACKUP DATABASE db_name TO d:db_namebackup
尝试再次连接到数据库。这次应该能够成功。
CONNECT TO db_name
恢复场景
理解故障出现的原因以及如何从故障中恢复是非常重要的。以下部分将模拟各种不同的故障类型,并介绍如何从故障中恢复系统。
场景 1. 整个数据库意外删除和损坏
本场景将展示如何从完全数据库故障中恢复。遇到这种情况的原因可以是数据库意外删除或受到破坏,也可以是人为错误或硬件故障造成的不一致性。在这些情况中,可以通过应用上次完全数据库备份对数据库进行恢复。该场景基于 表 1 中的配置。
表 1. 恢复场景中所使用的配置
组件 | 描述 |
---|---|
操作系统 | Windows XP Service Pack 2 / RHEL 4.0 |
DB2 版本和等级 | DB2 UDB Enterprise Server Edition (ESE) V8.2.6 fixpak 13 / DB2 V9.1 ESE fixpak 1 |
数据库名称 | TESTDB1 |
步骤 1. 执行完全数据库备份
要执行完全脱机数据库备份,可以使用以下命令:
TERMINATE
FORCE APPLICATION ALL
BACKUP DATABASE testdb1 TO c:testdb1backup
需要注意备份文件名称中生成的 ID。它类似于:20060411154219。这个 ID 只是备份映像的时间戳,恢复过程中需要使用它。
步骤 2. 模拟故障
要模拟故障场景,可以完全删除数据库:
TERMINATE
FORCE APPLICATION ALL
DROP DATABASE testdb1
现在,尝试连接数据库:
CONNECT TO testdb1
将报告以下错误,它提示找不到此数据库:
Error: SQL1013N Database alias name or Database name "testdb1" could not found.
步骤 3. 创建一个新的数据库
要开始恢复过程,首先创建一个与丢弃数据库名称相同的数据库:
CREATE DATABASE testdb1
查看数据库目录的内容,确保数据库创建成功且目录正确:
LIST DB DIRECTORY
步骤 4. 恢复数据库
恢复数据库备份映像。在本例中,我使用时间戳 20060411154219 恢复备份映像:
RESTORE DATABASE testdb1 FROM c:testdb1backup TAKEN AT 20060411154219 INTO testdb1
将返回以下报警消息
SQL2523W: Restoring to an existing database that is different from the database on the backup image. The target database will be overwritten by the backup version. The roll-forward recovery logs associated with the target database will be overwritten.
按 Y 键继续运行。该操作将把数据库备份恢复到前一步骤中创建的数据库。成功恢复映像之后,数据库将与备份时的数据库完全一致。
步骤 5. 连接到数据库
尝试连接到数据库:
CONNECT TO testdb1
可能会返回以下错误消息:
SQL1117N A connection to or activation of database "testdb1" cannot be made because of Roll-Forward Pending SQLSTATE=57019.
出现错误的原因可能是,必须使用某些日志文件进行一致性检查。使用以下命令将数据库恢复到一致状态:
ROLLFORWARD DATABASE testdb1 COMPLETE
再次尝试连接到数据库:
CONNECT TO testdb1
步骤 6. 数据库和对象验证
验证之前的对象仍然存在且可用,比如说:
LIST TABLESPACES SHOW DETAIL
LIST TABLES
上一条命令应该会提示,所有表空间均处于正常状态并且可以访问容器。所有表及表中的数据集合应该与执行备份时的状态一致。
场景 2. 表空间容器意外丢弃或损坏的表空间容器
本场景将展示当一个或多个表空间容器丢失或损坏时如何恢复数据库系统。出现此情况的原因可以是人为错误(比如说,某个用户删除了某个目录或文件)或数据文件损坏问题。本场景基于 表 2 中的配置。
表 2. 场景 2 中所使用的系统配置
组件 | 描述 |
---|---|
操作系统 | Windows XP Service Pack 2 / RHEL 4.0 |
DB2 版本和等级 | DB2 UDB Enterprise Server Edition (ESE) V8.2.6 fixpak 13 / DB2 V9.1 ESE fixpak 1 |
数据库名称 | TESTDB1 |
表空间名称 | TS1 |
TS1 中的容器 | c1.dat, c2.dat, c3.dat, c4.dat |
步骤 1. 获取定义的所有表空间的目录
CONNECT TO testdb1
LIST TABLESPACES SHOW DETAIL
步骤 2. 获取所有表空间容器信息的目录
LIST TABLESPACE CONTAINERS FOR 1 SHOW DETAIL
注意:上面命令中的 “1” 是本环境中表空间 TS1 的表空间 ID。它是通过之前 LIST TABLESPACES SHOW DETAIL 命令中的输出获得的。所使用的每个表空间 ID 都需要重复这个命令。
步骤 3. 备份表空间
TERMINATE
FORCE APPLICATION ALL
BACKUP DATABASE testdb1 TABLESPACE ts1 TO c:testdb1backupts1
如您所见。本场景假定用户对大多数重要的表空间都执行了备份(供恢复使用)。
步骤 4. 模拟表空间故障
手动模拟此场景,即表空间容器文件被某个用户意外删除:
DEL C:TESTDB1TS1C1.DAT
DEL C:TESTDB1TS1C2.DAT
DEL C:TESTDB1TS1C3.DAT
随后,当我们连接到数据库并尝试执行与表空间 TS1 相关的操作时,将返回错误。比如说:
CONNECT TO testdb1
CREATE TABLE tab1(c1 INTEGER) IN ts1
返回以下错误消息:
SQL0290N Table space access is not allowed.
还可以使用以下命令检查表空间状态:
LIST TABLESPACES SHOW DETAIL
删除容器后,上面的命令将显示 TS1 的状态为 0x400 ,该代码表示脱机且不可访问状态。由于删除了三个容器,因此表空间不再处于正常状态(0x000)。
如果再次执行 LIST TABLESPACE CONTAINERS 命令,可以验证哪些容器丢失或不可用:
LIST TABLESPACE CONTAINERS FOR 1 SHOW DETAIL
在结果中,容器 C1、C2 和 C3 的 Accessible 状态将显示为 No。
步骤 6. 恢复表空间备份映像
要恢复备份映像,可以使用以下命令:
TERMINATE
RESTORE DATABASE testdb1 TABLESPACE (ts1) FROM C:TESTDB1BACKUPTS1
步骤 7. 检查表空间状态
确保容器可以访问:
LIST TABLESPACES SHOW DETAIL
LIST TABLESPACE CONTAINERS FOR 1 SHOW DETAIL
如果恢复成功,表空间 TS1 的状态应该为正常(0x000)并且所有容器应该都可以访问。
步骤 8. 验证恢复是否成功
CREATE TABLE tab1(no INTEGER) IN ts1
注意:您可能会遇到以下这种情况:恢复表空间之后仍然需要进一步恢复操作。如果有任何日志文件修改未被应用(以确保数据库的一致性),都有可能出现这种情况。在这种情况下,使用以下任一命令完成恢复:
ROLLFORWARD DATABASE testdb1 COMPLETE
OR
ROLLFORWARD DATABASE testdb1 TO END OF LOGS AND STOP
以上命令将应用所有剩余的日志文件,从而将数据库恢复到一致状态。
场景 3. 某个表意外丢失
对于含有上千个表的数据库环境,难免会错误地丢弃某个表。在本场景中,您将看到如何恢复意外丢弃的表。要执行这种类型的恢复,必须将数据库配置为归档日志模式,并且可以使用完全数据库备份映像。要对丢弃的表执行恢复操作,表所在的表空间必须将 DROPPED TABLE RECOVERY 选项打开。可以在创建表空间的过程中设置此选项,也可以直接调用 ALTER TABLESPACE 语句。DROPPED TABLE RECOVERY 选项特定于表空间且局限于常规表空间。
本场景基于 表 3 中的系统配置。
表 3. 场景 3 中所使用的系统配置
组件 | 描述 |
---|---|
操作系统 | Windows XP Service Pack 2 / RHEL 4.0 |
DB2 版本和等级 | DB2 UDB Enterprise Server Edition (ESE) 8.2.6 fixpak 13 / DB2 9.1 ESE fixpak 1 |
数据库名称 | TESTDB1 |
表空间名称 | TS1 |
表名称 | TAB1 |
步骤 1. 执行完全数据库备份
TERMINATE
FORCE APPLICATION ALL
BACKUP DATABASE testdb1 TO c:testdb1backup
需要注意备份映像的时间戳。
步骤 2. 连接到数据库并执行生成日志记录的操作
CONNECT TO testdb1
CREATE TABLE tab1(no INTEGER) IN ts1
TERMINATE
ARCHIVE LOG FOR DATABASE testdb1
CONNECT TO testdb1
INSERT INTO tab1 VALUES(1)
INSERT INTO tab1 VALUES(2)
INSERT INTO tab1 VALUES(3)
COMMIT
TERMINATE
ARCHIVE LOG FOR DATABASE testdb1
CONNECT TO testdb1
INSERT INTO tab1 VALUES(4)
INSERT INTO tab1 VALUES(5)
COMMIT
TERMINATE
ARCHIVE LOG FOR DATABASE testdb1
CONNECT TO testdb1
SELECT * FROM tab1 /* check the 5 committed values from TAB */
步骤 3. 模拟意外丢弃表的场景
DROP TABLE tab1
COMMIT
SELECT * FROM tab1
将返回以下错误消息:
Error: SQL0204N "Administrator.TAB1" is an undefined name
步骤 4. 恢复数据库
要恢复已被丢弃的表,先恢复数据库备份,然后执行向前恢复(rollforward)操作:
TERMINATE
FORCE APPLICATION ALL
RESTORE DATABASE testdb1 FROM c:testdb1backup TAKEN AT 20070314144204 INTO testdb1
将返回以下消息:
SQL2539W Warning! Restoring to an existing database that is the same as the Backup image database.
The database files will be deleted.
Do you want to continue? (Y/N)
按 Y 键完成此过程。
步骤 5. 检索已丢弃表的对象 ID
使用以下命令检索意外丢弃的表的对象 ID:
LIST HISTORY DROPPED TABLE ALL FOR DATABASE testdb1
可以将返回的信息(比如说 清单 1 中显示的示例)复制到某个文本文件中以供未来引用。
清单 1. LIST HISTORY 命令返回的信息
Op Obi Timestamp Sequence Type Dev Earliest Log Current Log; Backup ID -- --- ------------------ ---- --- ------------ ------------ ----------------------------- D; T; 20070314142913;;;;;;000000000000892700050108 ------------------------------------------------------------------------------------------ "ADMINISTRATOR"."TAB1" resides in 1 table space(s): 00001 TS1 ---------------------------------------------------------------------------- Comment: DROP TABLE Start Time: 20070314142913 End Time: 20070314142913 Status: A ---------------------------------------------------------------------------- EID: 37 DDL: CREATE TABLE "ADMINISTRATOR"."TAB1" ( "NO" INTEGER ); IN "TS1" ; |
清单 1 中的 Backup ID 栏显示被丢弃表的 ID 为 000000000000892700050108。这一信息对于恢复表非常重要。
步骤 6. 向前恢复数据库
现在已经获得了被丢弃表的 ID,下一步需要使用该表的备份 ID RB 数据库,这样才能够导入表的数据。在向前恢复数据库之前,需要确保有一个目录可供存储导入数据,比如说 c:testdb1exporttab1。使用以下命令向前恢复数据库:
ROLLFORWARD DATABASE testdb1 TO END OF LOGS
AND STOP RECOVER DROPPED TABLE 000000000000892700050108 TO c:testdb1exporttab1
使用 END OF LOGS 选项的作用是让 DB2 在执行备份操作后应用所有可用日记文件。
步骤 7. 检查导入的数据文件
完成数据库向前恢复之后,需要检查在 ROLLFORWARD 命令中指定路径。应该能够找到一个 .TXT 文件,打开该文件并验证其中包含的数据与意外丢弃表之前的数据相同。
步骤 8. 连接到数据库并重新创建被丢弃的表
验证导出文件之后,我们需要重新创建被丢弃的表并重新填入数据。被丢弃表的定义包含在步骤 5 的 LIST HISTORY 命令的输出中。连接到数据库并执行 CREATE TABLE 语句:
CONNECT TO testdb1
CREATE TABLE "ADMINISTRATOR"."TAB1" ( "NO" INTEGER ) IN "TS1"
步骤 9. 导入数据
重新创建表之后,可以使用以下命令将数据库重新导入到表中:
IMPORT FROM c:testdb1exporttab1Node0000data.txt OF DEL INSERT INTO administrator.tab1
IMPORT 工具将导出文件中的所有数据导回到表中并在成功后发送报告(未显示)。
步骤 10. 验证恢复后的数据
确保 IMPORT 过程中没有错误或报警,并且所有数据都已导回表中:
SELECT * FROM tab1
如果一切运行正常,则意外丢弃点之前的所有数据应该都在表中。
场景 4. 恢复到时间点
如果某个表空间被丢弃或受到破坏,则定义在其中的表及数据将不可访问。要从此场景中恢复系统,需要一个可用的完全数据库备份映像并且需要将数据库配置为归档日志模式。本场景基于 表 4 中的系统配置。
表 4. 场景 4 中所使用的系统配置
组件 | 描述 |
---|---|
操作系统 | Windows XP Service Pack 2 / RHEL 4.0 |
DB2 版本和等级 | DB2 UDB Enterprise Server Edition (ESE) 8.2.6 fixpak 13 / DB2 9.1 ESE fixpak 1 |
数据库名称 | TESTDB1 |
表空间名称 | TS1 |
表空间 | TAB1 |
步骤 1. 执行完全数据库备份
TERMINATE
FORCE APPLICATION ALL
BACKUP DATABASE testdb1 TO c:testdb1backup
务必记录下备份映像文件接收到的时间戳,因为恢复过程需要使用它。
步骤 2. 创建一个新的表空间
创建一个新的表空间 TS1,以供本恢复场景使用:
CREATE TABLESPACE TS1 MANAGED BY DATABASE USING (FILE 'c:testdb1s4C1.dat' 1000 )
EXTENTSIZE 8 PREFETCHSIZE 24
确认表空间和相关容器都已创建:
LIST TABLESPACES
LIST TABLESPACE CONTAINERS FOR n SHOW DETAIL
其中,n 是 LIST TABLESPACES 输出中显示的表空间 ID。
步骤 3. 创建一个表并对它执行一些操作
创建表空间之后,创建一个名为 TAB1 的表并将它放到表空间中。在表中插入一些数据。为了让此场景更接近现实,使用一些命令强制 DB2 打开归档文件:
- CREATE TABLE tab1 (no INTEGER) IN TS1
- INSERT INTO tab1 VALUES(1)
- INSERT INTO tab1 VALUES(2)
- COMMIT
- TERMINATE
- ARCHIVE LOG FOR DATABASE testdb1
- CONNECT TO testdb1
- INSERT INTO tab1 VALUES(3)
- INSERT INTO tab1 VALUES(4)
- INSERT INTO tab1 VALUES(5)
- COMMIT
- SELECT * FROM tab1
- TERMINATE
- ARCHIVE LOG FOR DATABASE testdb1
- CONNECT TO testdb1
步骤 4. 模拟表空间故障
要在此场景中模拟一个故障,需丢弃表空间:
DROP TABLESPACE ts1
SELECT * FROM tab1
将返回以下错误消息:
SQL0204N Error table does not exist "Administrator.Tab1" is an Undefined Name.
步骤 5. 恢复数据库
丢弃表空间之后,这个表空间的所有内容也被丢弃。要恢复表空间,恢复上一次可用备份映像:
- TERMINATE
- RESTORE DATABASE testdb1 FROM c:testdb1backup
- TAKEN AT 20070315150901 INTO testdb1
在执行 RESTORE 命令时,需要使用在步骤 1 中记录的备份时间戳。将接收到以下报警消息:
SQL 2539W Warning! Restoring to an existing database that is same as the backup image database.
The database files will be deleted.
Do you want to continue? (Y/N)
按 Y 键继续执行。
步骤 6. 向前恢复数据库
恢复数据库之后,尝试连接到数据库:
CONNECT TO testdb1
将返回以下消息:
SQL 111N A connection to or activation of database cannot be made because of Roll-forward Pending. SQLSTATE=57019
在 RB 数据库之后,我们需要计算出丢弃表空间的时间戳。为此,使用 LIST HISTORY 命令:
LIST HISTORY CREATE TABLESPACE ALL FOR DATABASE testdb1
我们可以看到被丢弃表空间的准确时间戳。但是,不应该使用这个时间戳,因为需要使用在它之前的时间戳值恢复最近一次提交的值。
本示例将使用 20070315151500 作为时间戳来进行恢复。需要将该数据格式化为 ROLLFORWARD 工具可识别的形式,即 2007-03-15.15.15.00
ROLLFORWARD DATABASE testdb1 TO 2007-03-15.15.15.00 USING LOCAL TIME AND STOP
DB2 将应用指定时间戳之前的所有日志,并恢复数据库的表空间。
步骤 7. 验证已恢复的表空间和表
CONNECT TO testdb1
LIST TABLESPACES SHOW DETAIL
SELECT * FROM tab1
以上命令的结果允许我们确认表空间和表是否已恢复到指定的时间点。
结束语
本文介绍了可以在 DB2 中执行各种不同的日志。文章还演示了一些关键的恢复场景,并提供了从各类故障恢复系统的详细步骤。
对于任务关键型数据库,理解备份恢复的流程和意外故障的计划非常重要。同时,强烈建议将经过测试的备份和恢复计划应用到实践中。