none
请问SQLSERVER备份的原理 RRS feed

  • 问题

  • 我使用下面脚本来测试

    备份脚本

    USE master
    GO
    --创建数据库
    CREATE DATABASE LogChainTest;
    GO
    --改为完整恢复模式
    ALTER DATABASE LogChainTest SET RECOVERY FULL;
    GO
    
    
    --第一个完整备份
    DECLARE @strbackup NVARCHAR(100)
    --改为日期加时间的
    SET @strbackup = 'C:\LogChainTest_full1_'
        + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
                          ''), ':', '') + '.bak'
    BACKUP DATABASE LogChainTest TO DISK =@strbackup  WITH INIT;
    GO
    
    --第一个差异备份
    USE LogChainTest
    GO
    CREATE TABLE tt(id INT)
    INSERT INTO tt
    SELECT 1
    DECLARE @strbackup NVARCHAR(100)
    --改为日期加时间的
    SET @strbackup = 'C:\LogChainTest_diff_'
        + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
                          ''), ':', '') + '.bak'
    BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT, DIFFERENTIAL;
    GO
    
    --第一个日志备份
    USE LogChainTest
    GO
    INSERT INTO tt
    SELECT 2
    DECLARE @strbackup NVARCHAR(100)
    --改为日期加时间的
    SET @strbackup = 'C:\LogChainTest_log1_'
        + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
                          ''), ':', '') + '.bak'
    BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT;
    GO
    
    
    
    
    --第二个完整备份
    USE master
    GO
    DECLARE @strbackup NVARCHAR(100)
    --改为日期加时间的
    SET @strbackup = 'C:\LogChainTest_full2_'
        + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
                          ''), ':', '') + '.bak'
    BACKUP DATABASE LogChainTest TO DISK = @strbackup WITH INIT;
    GO
    
    
    --第二个日志备份
    USE LogChainTest
    GO
    INSERT INTO tt
    SELECT 3
    DECLARE @strbackup NVARCHAR(100)
    --改为日期加时间的
    SET @strbackup = 'C:\LogChainTest_log2_'
        + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120), '-', ''), ' ',
                          ''), ':', '') + '.bak'
    BACKUP LOG LogChainTest TO DISK = @strbackup WITH INIT;
    GO
    USE master
    GO
    
    
    --DROP DATABASE LogChainTest

    还原脚本

    --差异备份和日志备份打乱
    USE master
    GO
    --还原第一个完整备份
    RESTORE DATABASE LogChainTest FROM DISK='C:\LogChainTest_full1_20131205222715.bak' 
    WITH REPLACE , NORECOVERY
    GO
    
    --还原第一个日志备份
    RESTORE LOG LogChainTest FROM DISK='c:\LogChainTest_log1_20131205222720.bak' 
    WITH  NORECOVERY
    GO 
    
    --还原差异备份
    RESTORE DATABASE LogChainTest FROM DISK='c:\LogChainTest_diff_20131205222718.bak' 
    WITH NORECOVERY
    GO
    
    消息 3136,级别 16,状态 3,第 1 行
    无法还原此差异备份,因为该数据库尚未还原到正确的早期状态。
    消息 3013,级别 16,状态 1,第 1 行
    RESTORE DATABASE 正在异常终止。
    
    
    
    
    --还原第二个日志备份,没有报错
    RESTORE LOG LogChainTest FROM DISK='C:\LogChainTest_log2_20131205222726.bak' 
    WITH RECOVERY
    GO 
    
    
    
    
    --可以查询出id列有三行记录
    USE [LogChainTest]
    GO
    SELECT * FROM [dbo].[tt]

    我知道无论完整备份、差异备份、日志备份都会把备份时候的minlsn写入备份文件

    问题一:

    还原的时候根据这个LSN顺序来进行还原,如果调转还原顺序是会报错的,例如上面先还原第一个日志备份再还原差异备份

    还原差异备份的时候就报错

    既然报错了为什麽可以还原第二个日志备份??

    而且数据都没有丢失,可以查出三行记录,在差异备份时候的记录都可以查出来

    问题二:

    [msdb].[dbo].[backupset]这个表的具体作用是什么?

    难道是在你还原的时候给你显示一下备份点?

    还有,为什麽当我进行了第二个完整备份之后,还原界面就不同了,只显示出第二个完整备份和后面的第二个日志备份

    而没有显示先前的第一个完备,差异,第一个日志

    2013年12月5日 14:48

答案

  • After restoring from first log backup, sql knows last lsn recovered. That's why get error when tried to restore from diff backup because last lsn in it is earlier than lsn recovered.

    I never restore with gui, restore statement is much flexible.

    rmiao大侠这些我都知道

    如果按照rmiao大侠说的:那么只要还原的时候按照备份的顺序来还原就可以了

    可以只还原日志备份,就算中间有差异备份也可以不用还原这些差异备份?

    还有,既然差异备份不用还原,那么备份策略-》完整备份-》日志备份1-》日志备份2

    不是更简单吗?为什麽要有差异备份

    You save total restore time with diff backup. For instance, you have weekly full backup/daily diff backup/hourly log backup. To recover db to Friday 10am, only need restore full backup plus Thursday's diff back then log backups after that diff backup until 10am. Without diff back, you have to restore almost whole week's log backups.
    2013年12月6日 3:53
  • 是的,差异备份可以理解为辅助日志备份。因为Restore的时间其实就是停机时间,这个时间如果SLA无法Cover的话是很麻烦的事。因此在设计“还原策略(注意:不是备份策略)”的时候要考虑到Recovery Time Object,仅仅是日志备份的话只要结尾日志成功备份出来就能保证0数据损失,但停机时间就无法保证。

    此外,差异备份还有一个好处是,如果中间备份的某个日志出问题,则可以用差异备份COVER掉这部分出问题的日志。

    2013年12月6日 4:41
  • 尾日志备份实际上就是备份日志的尾部,确保没有日志丢失

    redo log的时候保证没有数据丢失

    谢谢宋一直以来的指点

    2013年12月6日 8:16

全部回复

  • After restoring from first log backup, sql knows last lsn recovered. That's why get error when tried to restore from diff backup because last lsn in it is earlier than lsn recovered.

    You can still restore from following log backups as long as lsn chains didn't break, full backup will not break it.

    Books online has details of backupset and purpose of it.

    I never restore with gui, restore statement is much flexible.

    2013年12月5日 16:36
  • After restoring from first log backup, sql knows last lsn recovered. That's why get error when tried to restore from diff backup because last lsn in it is earlier than lsn recovered.

    I never restore with gui, restore statement is much flexible.

    rmiao大侠这些我都知道

    如果按照rmiao大侠说的:那么只要还原的时候按照备份的顺序来还原就可以了

    可以只还原日志备份,就算中间有差异备份也可以不用还原这些差异备份?

    还有,既然差异备份不用还原,那么备份策略-》完整备份-》日志备份1-》日志备份2

    不是更简单吗?为什麽要有差异备份

    2013年12月6日 1:40
  • 刚才宋大侠说明了差异备份的存在原因

    [msdb].[dbo].[backupset]表(备份链)跟日志链完全没有关系

    备份链只是给你看进行了哪些备份

    实际上我们只需要日志备份就可以了,但是做还原策略的时候要考虑RPO和RTO

    做日志备份PRO有可能保证不了

    差异备份靠DCM页面,一个是复制粘贴,一个是redo log速度肯定不可比

    等会上传我的理解图,希望各位大侠可以指点一下是否正确


    2013年12月6日 2:13
  • 大家以为在backup log的时候需要加上backup option no_log或者truncate_only才能截断日志

    这个认识是错误的

    truncate_only是只截断日志但是不备份,在SQL2008的时候已经取消了这两个backup option

    而为什麽上面的实验可以查询出三行记录(数据没有丢失)

    --可以查询出id列有三行记录
    USE [LogChainTest]
    GO
    SELECT * FROM [dbo].[tt]

    是因为每次备份的时候都已经将日志备份到bak里面,sqlserver还原的时候通过redo log来还原数据,所以

    我有下面的备份策略-》完备1-》差备1-》日备1-》差备2-》日备2

    如果我丢失了 差备1、日备1、差备2
    只有完备1和日备2
    还原完备1和日备2
    数据都不会丢失 

    背后靠的是日志归档,把旧的日志归档到bak里面

    而截断日志大家都会有一个误解,就是先截断事务日志,然后把剩下来的日志备份到bak里面

    实际上sqlserver是先把旧的日志(不活动日志)先备份到bak里面,然后再截断

    我们备份的时候:第一次备份肯定是完备,那么后续的备份,无论是完备,差备,日备,

    bak里面的日志链记录了从数据库创建开始到备份的时候的last lsn的log record

    除非
    做了下面的三个操作之一
        由完整恢复模式或大容量事务日志恢复模式转为简单恢复模式
        从数据库镜像进行恢复
        备份日志时指定了NO_LOG 或 WITH TRUNCATE_ONLY(还好在SQL Server 2008中这个选项被取消了)

    http://tech.it168.com/a2012/0306/1320/000001320639_1.shtml

    在简单恢复模式下,每一次CheckPoint,都会去检查是否有日志可以截断.如果有inactive的VLF时,CheckPoint都会将可截断部分进行截断,并将MinLSN向后推.

    简单恢复模式下日志是不保存的(当事务结束后,相关的会被截断)。

    仅仅是用于保证事务回滚和崩溃恢复的用途.所以备份日志也就无从谈起,更不能利用日志来恢复数据库

    所以在简单恢复模式下,你是不能执行 backup log语句的,因为在简单恢复模式下根本没有日志给你

    归档


    2013年12月6日 3:50
  • 不知道我上面的理解对不对
    2013年12月6日 3:50
  • After restoring from first log backup, sql knows last lsn recovered. That's why get error when tried to restore from diff backup because last lsn in it is earlier than lsn recovered.

    I never restore with gui, restore statement is much flexible.

    rmiao大侠这些我都知道

    如果按照rmiao大侠说的:那么只要还原的时候按照备份的顺序来还原就可以了

    可以只还原日志备份,就算中间有差异备份也可以不用还原这些差异备份?

    还有,既然差异备份不用还原,那么备份策略-》完整备份-》日志备份1-》日志备份2

    不是更简单吗?为什麽要有差异备份

    You save total restore time with diff backup. For instance, you have weekly full backup/daily diff backup/hourly log backup. To recover db to Friday 10am, only need restore full backup plus Thursday's diff back then log backups after that diff backup until 10am. Without diff back, you have to restore almost whole week's log backups.
    2013年12月6日 3:53
  • 这个答案我已经知道了,谢谢rmiao大侠
    2013年12月6日 3:55
  • But you keep asking ...
    2013年12月6日 3:57
  • 是的,差异备份可以理解为辅助日志备份。因为Restore的时间其实就是停机时间,这个时间如果SLA无法Cover的话是很麻烦的事。因此在设计“还原策略(注意:不是备份策略)”的时候要考虑到Recovery Time Object,仅仅是日志备份的话只要结尾日志成功备份出来就能保证0数据损失,但停机时间就无法保证。

    此外,差异备份还有一个好处是,如果中间备份的某个日志出问题,则可以用差异备份COVER掉这部分出问题的日志。

    2013年12月6日 4:41
  • 尾日志备份实际上就是备份日志的尾部,确保没有日志丢失

    redo log的时候保证没有数据丢失

    谢谢宋一直以来的指点

    2013年12月6日 8:16