曝光一些关于数据库完全备份的错误

曝光一些关于数据库完全备份的错误



原文地址:
http://www.sqlskills.com/blogs/paul/post/Debunking-a-couple-of-myths-around-full-database-backups.aspx

今天我经过一些讨论,发现很多关于对数据库备份工作原理的错误理解。本博文将曝光这些错误。我已经和我的朋友Steve Schmidt检查过本文的每一点,Steve Schmidt最近十年来一直在存储引擎小组负责BACKUP/RESTORE命令的开发。
错误1 一个完整备份仅仅包括备份开始至结束期间的事务日志
当你恢复一个完整数据库备份时,你会得到一个事务一致的数据库。考虑这样这种情况:有一个活动的事务,它直到数据库备份完成之后才提交。如果备份文件中只是包含备份期间的发生的事务日志,那么如何回滚活动的事务呢?所以,它必须包含足够多的事务日志来回滚活动的事务。一个数据库备份包含的日志的起始LSN是下面三者中的最小值:
1)最后一个检查点的LSN。
2)最老的活动的日志的起始点的LSN。
3)最后的复制事务的LSN。

下面,我将举例证明给你看。我将创建一个数据库、将其设为完整恢复模式(FULL recovery)、开始一个事务、建立检查点、然后备份数据库。检查点能确保已经修改的页能写到硬盘中去。

CREATE DATABASE stopattest;
GO
ALTER DATABASE stopattest SET RECOVERY FULL;
GO
BACKUP DATABASE stopattest TO DISK = 'c:/sqlskills/stopattest.bck' WITH INIT;
GO
USE stopattest;
GO
CREATE TABLE t1 (c1 INT);
GO
BEGIN TRAN;
INSERT INTO t1 VALUES (1);
GO

此时在另外一个连接上进行另外一次完整备份。
BACKUP DATABASE stopattest TO DISK = 'c:/sqlskills/stopattest.bck' WITH INIT;
GO
msdb.dbo.backupmedia表会告诉我们备份中的相关的LSN(我在LSN中加了一些空格来分隔):
SELECT last_lsn, checkpoint_lsn, database_backup_lsn FROM msdb.dbo.backupset
WHERE database_name = 'stopattest';
GO
last_lsn                     checkpoint_lsn           database_backup_lsn
---------------------     ---------------------        ---------------------
21 0000000190 00001   21 0000000174 00037    21 0000000058 00037
你看到了备份的检查点开始于(21:174:37)。备份中包含的第一条日志是(21:58:37),明显它是遭遇备份的。备份包含直到(21:190.:1)的所有的日志。让我们来看看这些LSN对应的实际的事务日志。

SELECT [Current LSN], Operation, [Transaction Name] FROM fn_dblog (null,null);
GO
下面是选出的一些输出:
Current LSN                    Operation            Transaction Name
------------------------       ----------------        ------------------
00000015:0000003a:0025    LOP_BEGIN_CKPT     NULL
(这是计算出的备份必须包含的最小的LSN(21:58:37),对应的十六进制就是(15:3a:25))

00000015:00000061:0001   LOP_BEGIN_XACT   user_transaction
(这是事务开始的地方,在备份动作开始之前但是包含在备份文件中)

00000015:000000ab:0004   LOP_BEGIN_XACT   Backup:InvalidateDiffMaps
(备份清除了差异备份位图)

00000015:000000ae:0025  LOP_BEGIN_CKPT    NULL
(BACKUP做的检查点,和上面的检查点的LSN是一致的。)

上面我们清楚地看出备份文件包含了比从备份开始更多的事务日志。

错误2 可以仅仅在一个完整备份使用STOPAT命令
这个错误是说可以对完全备份使用STOPAT命令,让数据库停在备份期间的某个点上。这个错误讨论是源自于:一个完整备份会包含备份期间所发生修改的日志,所以就可以停止在任何时间点上。理论上,这是正确的,但是事实上它是错误的——你不能仅仅就依靠一个数据库备份就让它停在备份发生期间的任何点上。
解释这个问题比较复杂。STOPAT操作将数据库置于某个LSN/时间点时的状态,在该点后面操作并不影响到数据库。备份命令会读取可能在备份期间修改或未修改的页。如果是修改的话,可能发生在备份期间的任何点。
假如X页“正好”在备份完成前的LSN(10:45:12)处发生了修改,在LSN(10:45:13)时被读取并备份。这样备份就包含了修改后的数据页和修改动作的日志记录。如果我要停在X页被修改前,比如LSN(10:44:00),该怎么办呢?因为备份只包括LSN(10:45:12)修改后的X页的映像。该如何回到我想停止的点上呢?讨论点集中在:我们拥有备份时修改的日志记录,难道SQL Server不能回滚吗?
是的,不能回滚,它甚至都看不到它。STOPAT将数据库备份恢复到一个指定的点上。如果我们要求恢复到LSN(10:44:00),那么日志只会读取并恢复到那个点上。然而因为备份直到LSN(10:45:13)才读取页X,所以它只有(10:45:12)修改后的映像。所以很明显,不会给我数据库在(10:44:00)时的数据库映像。
只有一个方法来将数据库停在一个指定的时间/LSN上,那就是拥有所有在这个时间/LSN前面的数据库映像(比如,前面的数据库备份)。然后再恢复所有的事务日志直到(包括该点)指定的时间/LSN点。
希望上面对你有所帮助。

你可能感兴趣的:(sql,数据库,server,活动,null,database,disk)