1.1  日志文件与数据文件一致性

一.备份概述

  数据安全是数据库的生命,数据库在使用过程中难免会遇到如:使用者的误操作或是被恶意修改,硬件故障导致数据文件无法被访问,自然灾害导致机房在物理上的损毁。本章从备份与恢复的功能作为解决问题的切入点。在实际工作中会遇到:使用什么样的备份策略(比如完整备份,文件备份,差异备份,日志备份),如何减少备份恢复时间(比如尽快恢复上线),如何将数据库恢复到想要的时间点(比如恢复到误操作以前),如何迁移数据库系统到一台新机器(比如用户账号,密码,任务脚本备份还原)。

  1.备份类型

     在sql
server数据库里包括数据文件和日志文件,相应包括数据备份和日志备份。数据备份可以是完整数据库备份,文件备份,差异备份也叫增量备份。日志备份也叫事务日志备份。

完整备份

   会记录数据库里的所有信息,可以将数据库数据恢复到某个时间点的状态。但一个大的数据库备份可能

需要很长时间。假如每天或每小时只用完整备份类型就需要发费大量存储空间和备份恢复时间,仅完整备份不能满足用户需求。

文件备份

   备份一个或多个文件或文件组的所有数据,多数针对大型数据库。文件备份+日志备份=完整备份。如果是一个文件损坏,只需还原该文件,从而加快恢复速度。

差异备份                              要求数据库之前做过一次完整备份称为基准。它是完整备份以后,发生更改的数据. 便于频繁备份,降低数据丢失的风险。
日志备份   要求数据库之前做过一次完整备份,自从上次完整备份或日志备份以后写入的日志记录。连续不断的日志链可以将数据库还原到任意时间点。 所以在备份策略中扮演重要角色。

   2.  备份策略

    (1)数据库最多能容忍多长时间的数据丢失。
    (2)投入多少人力物力做数据库备份和恢复策略。每次备份都会有时间间隔,数据丢失容易发生在最近一次备份之后的所有数据库操作,之后如文件损坏数据库需要恢复,备份尾日志肯定不成功,数据也会丢失,
为了保证数据不丢失需要引用镜像等技术。
    (3)
备份文件越多,数据库恢复的文件也越多,要建立一个合适的备份管理制度。备份虽然不会阻塞数据库的正常操作,但会产生一系列的磁盘读写,这时要避免在服务器I/O繁忙时。备份越多,失败的概述也会越大,需要管理员及时处理错误,将备份任务恢复常态。

  3. 常用的备份方法

分级

数据备份

日志备份

数据库级

完整数据库备份

差异数据库备份

日志备份

文件级

完整文件备份

差异文件备份

 

一.概述

  当数据库发生损坏,数据库的每个文件都能打开,只是其中的一些页面坏了,这种情况可以借助DBCC
CHECKDB进行数据库检查修复。如果要保证数据库不丢失,或修复不好,管理员只能做数据库完整恢复,为了少数页面恢复整个数据库,代价是比较高的,sql
server引入了页面还原功能,可以指定还原若干页面,从而能够大大节省数据库恢复时间。
  页面还原用于修复隔离的损坏页面,还原恢复时间比文件更快,减少了还原过程中处于离线的数据量,当某个文件的大量页面都出现损坏,可以直接还原该文件(需要有文件备份)。要进行还原的页面是在访问该页面,遇到错误而标记为”可疑”,可以试试去找msdb.dbo.suspect_pages表。在页面还原后,也需要恢复所有的日志文件备份
  1.1 还原的限制,不能还原的页
    (1)事务日志不能还原。
    (2)分配页面:全局分配映射GAM页面,共享全局分配映射SGAM页面和可用空间PFS页面,这些系统页面损坏,页面还原无法恢复。
    (3)所有数据文件的页面0 的(文件启动页面)。
    (4)页面1:9的(数据库启动页面)。
  1.2 还原条件
    (1) 必需使用完整恢复模式。
    (2) 只读文件组中的页面无法还原。
    (3) 还原顺序必须是从完整备份,文件备份中恢复页面开始。
    (4) 页面还原需要截止到当前日志文件的连续日志备份
    (5) 数据库备份和页面还原不能同时进行。

一.概述

  前面介绍了简单恢复模式和大容量恢复模式,这篇继续写完整恢复模式下的备份与还原。在完整恢复模式里最大的优点是只要能成功备份尾日志,就可以还原到日志备份内包含的任何时点(“时点恢复”)。当然对比前二种模式它是牺牲了磁盘I/O性能。

恢复模式

备份策略

数据安全性

I/O性能

简单恢复

完整备份+差异备份

安全最差。最后一次备份之后,所有数据操作丢失。

最优

大容量恢复

完整备份+差异备份+日志备份

折中。批量操作有丢失风险。尾日志备份失败。最后一次备份之后,所有数据操作丢失

折中

完整恢复

完整备份+差异备份+日志备份

相比上面二种最安全。尾日志备份失败。最后一次备份之后,所有数据操作丢失

最差

  在完整恢复模式下,最常见的备份策略,如下图所示:图片 1

一.概述

  前面讲了备份的一些理论知识,这篇开始讲在简单恢复模式下的备份与还原。在简单模式下是不能做日志备份的,发生灾难后,数据库最后一次备份之后做的数据修改将是全部丢失的,所以在生产环境下,数据又很重要,一般不建议使用这种模式。
例如对一个数据库有5次完整数据备份,时间是t5,  之后发生灾难,就会部丢失。

图片 2

  当数据库越来越大,完整备份时间会越来越长,为了减少丢失风险,引入差异备份。例如下图演示:在第一次建立数据库完整备份后,建立了三次差异备份,之后再建立完整备份,从而建立新的差异基准。不管是完整备份还是差异备份,一般只能在晚间进行。如果数据比较庞大又不允许长时间数据丢失,那简单恢复模式是不能满足的。

图片 3

 在上一章备份与恢复里了解到事务日志的重要性,这篇重点来了解事务日志。
事务日志记录了数据库所有的改变,能恢复该数据库到改变之前的任意状态。在sql
server实例每次启动时都会去检查数据文件与日志文件的一致性。
包括日志记录的任何已提交的数据必须体现在数据文件上,未被标记为已提交的将禁止写入数据文件,日志还存储了收到客户端回滚事务请求,sqlserver出错如死锁等,日志产生一个rollback命令。

二. 数据库恢复模式下的备份类型

    上面说了备份涉及的几种类型,这里就得说数据库恢复模式对备份类型的支持及特点。sql
server有三种数据库恢复模式设置包括:简单恢复模式,完整恢复模式,大容量恢复模式。

图片 4

  2.1  简单恢复模式
    在简单恢复模式下,不能做日志备份,只支持最简单的备份和还原方式,容易管理,数据库最后一次备份之后做的数据修改将全部丢失。为了降低风险,可以引入差异备份。差异备份的开销一般都比完整备份低,可以经常运行。如果数据库比较庞大或者不允许长时间的数据丢失,那这种简单恢复模式就不适合。在总结下:

    优点:

    (1)日志文件占用物理空间少日志增长慢。

    (2)对SQL执行性能优,能最小化日志。

    缺点:

    (1)不支持日志备份.

    (2)无法实现零丢失,恢复时间点至上一次备份时。

    (3)切换到其它恢复模式时,日志链中断。

  2.2 大容量恢复模式

    又叫大批量恢复模式,可以使用日志备份,它能够对某些大批量操作提供最佳的性能和最小的日志使用空间,这些大批量包括bulk
insert, bcp,create index, select into, writetext ,
updatetext。也就是说这些操作有数据丢失风险,相对完全恢复模式,这些操作都是完全记录的。总结下:

     优点:

         (1)日志文件占用物理空间少(日志增长慢)。

         (2)对SQL执行性能优(最小化日志)。

         (3)支持切换到完整模式不中断日志链。

    缺点:

         (1)还原大批量操作,数据有丢失风险如bulk insert, select
into等。

  2.3 完整恢复模式

    也可以叫完全恢复模式,在此模式下,所有操作都会被完整记录下来,如insert每新增的一行,delete每删除的一行,还包括大批理操作如bulk
insert等,都会记录到事务日志中。 包括create
index操作也会被完全记录,在日志恢复时不必要重建索引,恢复会很快。使用日志备份,可以定义一种很频繁的频率,5份钟甚至更短时间来做备份,以防止出现故障数据丢失。但是备份数量越多,恢复时需要严格按备份产生的顺序依次恢复,中间不能有任何备份缺失。

    优点:

    (1)
使用了日志备份可以实现零丢失(如果能进行尾日志备份,能还原到任意时间点)。

    (2)支持切换到大容量模式不中断日志链。

    缺点:

    (1)日志文件空间占用大必须定期日志备份,达到日志空间重用。

二.还原步骤      

  (1) 获取要还原的损坏页面的页ID,当sql
server遇到校验或残缺写错误时,会返回页面编号。可以通过查询msdb数据库里的suspect_pages表,或者监视事件和errorlog文件里记录的错误信息,查找到损坏的页面ID。
  (2)
从包含页的完整数据库备份,文件备份或文件组备份开始进行页面还原。在restore
database 语句中,使用page子句列出所有要还原的页ID。
  (3) 应用最近的差异备份。
  (4) 应用后续的日志备份。
  (5) 创建新的数据库尾日志备份。
  (6) 还原新的尾日志备份,应用这个新的日志备份后,就完成了页面还原。

二. 备份

  在前章中讲到了大容量恢复模式下的备份。备份策略与大容量模式是一样的,同样是完整备份+差异备份+日志备份。这里要突出点是:当误操作发生后,如何还原到误操作之前的一分钟,找出误操作之前的数据。
在”sql server
日志文件结构及误操作数据找回”中有介绍误操作数据找回,但是基于第三方工具ApexSQL
Log。虽然该工具方便,但要收费哟。

  我这里有一个BackupTest库,库里有个Employees表

use master
--设置完全模式
ALTER DATABASE BackupTest SET  RECOVERY FULL  
--创建备份设备(有就不要执行)
use master
exec sp_addumpdevice 'disk', 'BackupTestDevice','F:\SqlService\backup\BackupTestBackup.bak'
go
--做一次完整备份到备份设备中(备份基准)
backup database  BackupTest to BackupTestDevice

--新增数据
insert BackupTest.dbo.Employees values('湖南长沙')
insert BackupTest.dbo.Employees values('湖南湘潭')
--日志备份
backup log BackupTest to BackupTestDevice

 备份集如下所示:

图片 5

-- 误操作发生, 忘记加where条件,操作时间是:2018-8-12 10:55  
delete from BackupTest.dbo.Employees 

二.备份演示

  在简单恢复模式下主要的备份是完整备份和差异备份。我这里有TestLog库,库里有二个表。假设周日做一次完整备份,周一到周六晚上每天做一次差异备份,到第二周的周日时开始新的基准线。如下所示

use test
exec sp_addumpdevice 'disk', 'BackupTestDevice','F:\SqlService\backup\BackupTestBackup.bak'

  图片 6

--设置恢复模式为简单恢复
 ALTER DATABASE TestLog SET RECOVERY simple
go
-- 做一次完整备份到备份设备中(备份基准) 假设在周日晚上
backup database  TestLog to BackupTestDevice
go

图片 7

go
--差异备份 周一晚
backup database TestLog to BackupTestDevice with differential 
go
--差异备份 周二晚
backup database TestLog to BackupTestDevice with differential 
go
--差异备份 周三晚
backup database TestLog to BackupTestDevice with differential 
go
--差异备份 周四晚
backup database TestLog to BackupTestDevice with differential 
go
--差异备份 周五晚
backup database TestLog to BackupTestDevice with differential 
go
--差异备份 周六晚
backup database TestLog to BackupTestDevice with differential 
go
--完整备份 周日晚(新基准)
backup database TestLog to BackupTestDevice with differential 
go
--差异备份 周一晚
backup database TestLog to BackupTestDevice with differential 

 在备份设备中查看备份集
  图片 8

-- 通过脚本查看

select distinct
s.first_lsn,s.last_lsn,s.database_backup_lsn,s.position,
s.backup_finish_date,s.type,y.physical_device_name,s.backup_size
from msdb..backupset as s inner join
msdb..backupfile as f on f.backup_set_id=s.backup_set_id inner
join
msdb..backupmediaset as m on s.media_set_id=m.media_set_id inner
join
msdb..backupmediafamily as y on m.media_set_id=y.media_set_id
where s.database_name=’TestLog’
order by s.position asc

图片 9

 

   事务日志是在数据库创建或改变时与数据库关联起来的一个或多个文件。
任务改变数据库的操作都会在事务日志中写入描述这些改变的记录,包括要改变的页码,增加或删除的数据值,事务信息,起止的日期和时间信息等。通过dbcc
log可以看到如下信息

三. 备份

  为了演示损坏的数据页面,新建一个PageTest表,初始化三个PAGE页,后面人为的破坏一个数据页面。

use BackupPageTest
-- 创建表
create table PageTest
(
    ID int,
    name varchar(8000)
)
-- 产生
insert into PageTest
select 1, REPLICATE('a',8000)
insert into PageTest
select 1, REPLICATE('b',8000)
insert into PageTest
select 1, REPLICATE('c',8000)

 sys.system_internals_allocation_units 查看分配页情况

 图片 10

/* 
第1个参数:库名
第2个参数:表名
第3个参数:-1: 显示所有IAM、数据分页、及指定对象上全部索引的索引分页
PageFID: 文件ID
PageType=1 指数据页面
PageType=10 IAM页面
*/ 
-- 未公开的命令,语法如下:
DBCC IND(dbname,tablename,-1)

三.还原(1)

  当误操作发生后,是需要找管理员来进行数据还原。
如果数据库太大,还原是需要很长时间(注意使用副本,不要使用生产库)。
这种情况下就需要等待了。 避免的方法:(1)是做sql审核,不在Managemnet
studio里直接操作,避免此类事情发生.(2)是使用粒度更小的备份方式,但相应的复杂些。

--步骤1 备份尾日志
use master
go
backup log BackupTest to BackupTestDevice with norecovery 

图片 11

go
--步骤2 从备份恢复一个全备份 ,norecovery(正在还原...)不可读写. file指备份集位置号
restore database BackupTest from BackupTestDevice with file=19, norecovery --事务不恢复

--步骤3 
restore log BackupTest from BackupTestDevice  with file=20,  norecovery --事务不恢复

--步骤4 用stopat恢复到10:54
restore log BackupTest from BackupTestDevice  with file=21, stopat='2018/8/12 10:54', recovery --事务恢复

--数据又回来了
select * from  BackupTest.dbo.Employees 

  图片 12

三. 还原演示

   将一个数据库还原,需要构造一个正确的还原顺序。在还原过程中,备份文件结尾使用norecovery事务不恢复(正在还原。。)不可读写,在最后一个备份文件结尾使用recovery事务恢复。数据库恢复正常。

-- 切换到master库
use master

--设置单用户模式(否则执行下面报错:“因为数据库正在使用,所以无法获得对数据库的独占访问权”)
ALTER DATABASE TestLog SET OFFLINE WITH ROLLBACK IMMEDIATE

-- 从备份恢复一个全备份 ,norecovery(正在还原...)不可读写. file指备份集位置号
restore database TestLog from BackupTestDevice with file=1, norecovery 

  图片 13图片 14

-- 恢复到差异备份文件3,跳过差异备份2 ,看是否备份成功
restore database TestLog from BackupTestDevice  with file=3, recovery

  图片 15图片 16

-- 备份结束之后,结束单用户模式
ALTER  database  TestLog  set   online  

 下面在来演示还原差异文件,使用旧基准。还原看会怎么样

-- 从旧基准中恢复一个全备份 ,norecovery(正在还原...)不可读写. file是1
restore database TestLog from BackupTestDevice with file=1, norecovery 

--新基准file是8, 恢复到差异备份文件9 
restore database TestLog from BackupTestDevice  with file=9, recovery

图片 17

 

 总结:对于简单恢复模式,没有日志备份,恢复只需要一个完整数据库备份,以及最后一个差异备份。
对于多个差异备份文件,在还原时不需要LSN的连续性(在同一个基准内)。

图片 18

  图片 19

use master
-- 完整备份
backup database  BackupPageTest to BackupTestDevice

四.还原(2)

  在前面介绍中,有讲过,完整恢复模式切换到大容量模式,日志链是不会中断。下面来验证

--从完整恢复模式切换到大容量模式
ALTER DATABASE BackupTest SET  RECOVERY bulk_logged 
-- 新增
insert BackupTest.dbo.Employees values('湖南株洲')
--日志备份
backup log BackupTest to BackupTestDevice
-- 删除
delete from BackupTest.dbo.Employees 

-- 尾日志
backup log BackupTest to BackupTestDevice with norecovery 

 备份集如下所示,日志文件ID:22是在大容量模式下备份的,23是尾日志

图片 20

restore database BackupTest from BackupTestDevice with file=19, norecovery --事务不恢复
restore log BackupTest from BackupTestDevice  with file=20,  norecovery --事务不恢复
restore log BackupTest from BackupTestDevice  with file=21,  norecovery --事务不恢复
restore log BackupTest from BackupTestDevice  with file=22,  recovery 

  当日志还原到文件ID:22时,报错,如下图所示

图片 21

   跳过文件ID:22, 使用23来提交事务,也会报错,如下所示:

restore log BackupTest from BackupTestDevice  with file=23,  recovery

图片 22

   经过测试,还原失败,错误是指:与上一次还原到指定时间点有关系。

  下面在测试一个新库TestFULLToBulk

--设置完全模式
ALTER DATABASE TestFULLToBulk SET  RECOVERY FULL  
--做一次完整备份到备份设备中(备份基准)
backup database  TestFULLToBulk to BackupTestDevice
insert TestFULLToBulk.dbo.product values('湖南株洲')
--日志备份
backup log TestFULLToBulk to BackupTestDevice
--设置大容量
ALTER DATABASE TestFULLToBulk SET RECOVERY bulk_logged   

insert TestFULLToBulk.dbo.product values('湖南湘潭')
--日志备份
backup log TestFULLToBulk to BackupTestDevice

  备份集如下:文件ID28是在大容量下进行的备份

  图片 23

backup log TestFULLToBulk to BackupTestDevice with norecovery 
go
restore database TestFULLToBulk from BackupTestDevice with file=26, norecovery 
go
restore log TestFULLToBulk from BackupTestDevice  with file=27,  norecovery 
go
restore log TestFULLToBulk from BackupTestDevice  with file=28,  recovery 

  上面还原成功,证明了完整恢复模式切换到大容量模式,日志链是不会中断。

 

  sql server里每个日志记录都有一个唯一的日志序列号标识LSN,
同一个事务里的所有日志记录是一个连接起来的整体,这样能够容易的定位一个事务的各个部分,从而实现撤销undo或重做redo操作。

四 模拟页面损坏

  使用PagePID为89的数据页面进行演示,通过dbcc
page查看该页面,知道该页数据是存储的第三条数据。

dbcc traceon (3604)
dbcc page('BackupPageTest',1,89,1)

  图片 24

  使用 dbcc wirtepage来模拟该面损坏:

-- 未公开的命令语法为如下
dbcc writepage ({ dbid, 'dbname' }, fileid, pageid, offset, length, data)

-- 模拟页面损坏
dbcc writepage(BackupPageTest,1,89,96,10,0x65656565656565656565)

图片 25

-- 查询该表时,第三条数据显示NULL
select * from PageTest

  1.2 优先写日志

  图片 26

--更新第三条数据,结果报错
update PageTest set  id=2  where ID is null

  图片 27

-- 插入第4条是成功的
insert into PageTest
select 4, REPLICATE('d',8000)

  图片 28

  在日志里有个名词叫“优先写日志”。是指:缓存管理器能够保证日志写入磁盘优先于相应的数据改变写入磁盘,这叫优先写日志。一旦某个数据页发生改变,相应的日志项的LSN将会被写入该数据页的页头,缓存管理器能够保证日志页以特定的顺序写入磁盘,使得无论故障在何时发生,sqlserver
能清楚知道在系统故障之后应该处理哪些日志块。如下图所示

五. 获取要修复的数据页面 

-- 使用checkdb检查
DBCC CHECKDB(BackupPageTest)

  通过校验,提示无法处理面(1:89)如下图

  图片 29

图片 30

六. 还原

use master
--从完整数据库备份,开始还原,指定要还原的PAGE页
restore database BackupPageTest page='1:89' from BackupTestDevice with file=39,  norecovery
--创建新的尾日志备份
backup log BackupPageTest to BackupTestDevice

 
 此时访问数据表PageTest将会发错,如下图所示,表明在还原过程中数据是不可访问的。

 图片 31

图片 32

--最后还原新的尾日志备份
restore log BackupPageTest from BackupTestDevice with file=40,  recovery

   数据修复过来了,如下图:

  图片 33

  再次CHECKDB 检查表状态

  图片 34

   但一个事务日志记录被写入到磁盘,实际上被更改的数据可能还未来得及写入数据页,对于事务日志写操作是异步的,数据页的写操作也是异步的,但数据页不需要立即完成,因为日志包含了用来重做这些写操作的所有信息。

  1.3 日志文件与重启恢复
  在sqlserver错误日志 error log
里会报告每个数据库重启恢复的进展,它会告诉我们每一个数据库有多少事务被前滚,多少事务被回滚,
有时被称为“崩溃”恢复,因为sqlserver崩溃或服务异常停止,需要恢复过程在服务重启时运行。
如果sqlserver里 事务日志与数据文件一致,则重启服务很快。

    图片 35

  1.4 日志文件redo与undo

  如果事务在提交时,sql
server服务突然停止,数据还未来得及写入数据页(注意不是磁盘),当服务启动,该事务必须前滚,根据事务日志所指示的更改来重做事务,这称为恢复的重做(redo)阶段。

  如果一个检查点checkpoint 在事务提交前发生,
它将会把未提交的更改写入磁盘,随后sql server服务在提交前被停止,
恢复过程将会找出未提交事务对数据的改动,该过程必须撤销反映在事务日志中的改动,回滚所有不完整事务称为恢复的撤销(undo)阶段。

  1.5 改变日志文件大小

    数据库管理员为了控制文件在大小,可能有时候要收缩文件空间可以使用dbcc
shrinkdatabase或 
dbcc 
shrinkfile。shrinkdatabase
是收缩指定数据库中的所有数据文件和日志文件大小。shrinkfile
是收缩当前数据库的指定数据文件或日志文件的大小。注意的是不能在备份数据库时收缩数据库。 反之,也不能在数据库执行收缩操作时备份数据库。收缩一般在数据库维护时段可以进行。使用dbcc 
shrinkfile来一个文件一个文件地做比较稳妥。

-- 验证文件是否有足够的可用空间可供删除
SELECT name ,size/128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS int)/128.0 AS AvailableSpaceInMB
FROM sys.database_files;

  1.6 虚拟日志文件VLF

  在前面“sql server
日志文件结构及误操作数据找回”中讲过每个物理日志文件是分成多个虚拟日志单元,虚拟日志单元没有固定大小,且数量不固定。可以通过dbcc
loginfo来观察虚拟日志文件的关键属性。当我们在当前数据库下运行dbcc
loginfo,会为每个VLF返回一行记录。

use test
dbcc loginfo

  图片 36

  上面是查看了test库日志文件里的VLF,  Fileld是指物理日志文件ID,这里test只有一个日志文件。
FileSize是文件大小(byte), StartOffset是指起点偏移(byte)。第一个VLF
是包含页头信息而不是日志记录,VLF从第二页开始。Status
表示该VLF是否可被重用,状态2表示该VLF或者是活动的或者是可恢复的,状态0表示该VLF是可复用的或者完全没有被使用过。通过备份事务日志会改变可恢复的VLF到可复用状态也就是状态为0.

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图