在实际生活和工作情况下,为了保证数据库安全需要经常进行数据库的备份和还原操作.我们可能会遇到各种各样的数据库异常状态,如何判别异常状态,如何迅速而安全有效地把系统和数据恢复到正常状态,是系统管理员不可缺少的工作,是衡量系统管理员水平高低的一把尺子.在本章我们将会讲到数据库的恢复模式、几种备份操作和几种还原操作.
数据库的恢复模式是指数据库遭到破坏时还原数据的策略,一般地,SQL server提供了以下三种恢复模式:
完整恢复模式是等级最高的恢复模式.在完整恢复模式中,对数据库的任何操作都记录在事务日志里.当数据库遭到破坏后,可以使用该事务日志迅速恢复数据库.由于事务日志巨细无遗地记录下了对数据库的所有操作,因此完整恢复模式可以将数据库恢复至任意一个时间点.但是,这种恢复模式将带来巨大的事务日志文件,极其消耗磁盘空间.因此,若不是事务日志非常重要的数据库,一般不采用完整恢复模式.
大容量日志记录的恢复模式的事务日志文件远小于完整恢复模式,这是因为它不记录一些非常消耗空间的操作,如:CREATE INDEX、BULK INSERT、BCP和SELECT…INTO.这种备份方式是最常用的,虽然不可以完全还原数据库,但是可以在事务日志消耗空间和还原完整程度上取一个折中,是非常划算的.
简单恢复模式适用于一些小型数据库,这些数据库通常不会有大量数据变更.数据只能还原到进行备份的时刻点,而备份之后的操作数据将会丢失并需要重建.这种模式的特点是数据库不维护事务日志,好处是最小的磁盘空间占用,以及简单的恢复操作.
为了将数据库安全完整地备份下来,应该在备份之前制定一个完善的备份计划,确保数据库安全.备份计划的制定应考虑如下内容:
备份的目的在于当系统出现故障时快速而完整地恢复系统,因此有必要将数据完整备份下来.大体上看,备份对象分为两个方面: 系统数据库和用户数据库.统数据库存储了SQL server系统和全部用户数据库的信息,对系统数据库的备份主要指对master
、msdb
、model
数据库的备份.master
数据库保存了SQL server系统和全部用户数据库的信息,如用户账户、可配置的环境变量、系统错误信息等.msdb
数据库保存了有关SQL server Agent服务的记录.model
数据库为新的用户数据库提供了模板.
用户数据库保存了一切用户相关的业务数据,其内容一定不可以丢失,必须充分保护用户数据库的数据安全.从某种意义上说,系统数据库可以丢失,用户数据库一定不能丢失.建议在以下操作进行后,对用户数据库进行备份:
动态备份时允许用户在备份时使用数据库.动态备份时,SQL server执行如下操作:
虽然说动态备份允许备份时操作数据库,但是多用户操纵数据库必然会对备份的性能有所影响,同样也会反作用于数据操作的性能,使得两边都进行得慢,因此,应该将备份安排在用户操作不那么活跃的时间段.且以下的操作不允许在备份时进行:
如果在执行这些禁止的操作时启动备份,则备份失败,如果在备份时执行这些禁止的操作,则这些操作执行失败.
在执行备份操作时,既可以指定永久备份文件,也可以指定临时备份文件.选择好备份文件的类型,在将其备份到指定文件上即可.
在SQL server中,永久的备份文件,也称为备份设备.如果希望所创建的备份文件反复使用或执行系统的自动化操作,例如: 自动备份数据库,则需要使用备份设备.有两种创建备份设备的方法: T-SQL语句或SSMS,这里使用T-SQL进行操作,其基本语法如下:
sp_addumpdevice 'device_type', 'logical_name', 'physical_name';
其中divece_type有两种(DISK或TAPE),然后指定备份设备逻辑文件名和物理存储位置,如下例:
USE ElecTravelCom;
GO
EXEC sp_addumpdevice 'DISK','ElecTravelComBackupFile','F:\MyBackupDataBase\ElecTravelComBackupFile';
GO
运行结果如下:
注意: 创建备份设备之后并不会马上在磁盘内写入,只有执行备份操作后磁盘内才有备份设备文件.
如果希望创建临时备份文件,并希望灵活地备份,则应该使用BACKUP语句,其备份的基本语法如下:
--Backing Up a Whole Database
BACKUP DATABASE { database_name | @database_name_var }
TO <backup_device> [ ,...n ]
[ <MIRROR TO clause> ] [ next-mirror-to ]
[ WITH { DIFFERENTIAL
| <general_WITH_options> [ ,...n ] } ]
[;]
--Backing Up Specific Files or Filegroups
BACKUP DATABASE { database_name | @database_name_var }
<file_or_filegroup> [ ,...n ]
TO <backup_device> [ ,...n ]
[ <MIRROR TO clause> ] [ next-mirror-to ]
[ WITH { DIFFERENTIAL | <general_WITH_options> [ ,...n ] } ]
[;]
--Creating a Partial Backup
BACKUP DATABASE { database_name | @database_name_var }
READ_WRITE_FILEGROUPS [ , <read_only_filegroup> [ ,...n ] ]
TO <backup_device> [ ,...n ]
[ <MIRROR TO clause> ] [ next-mirror-to ]
[ WITH { DIFFERENTIAL | <general_WITH_options> [ ,...n ] } ]
[;]
--Backing Up the Transaction Log (full and bulk-logged recovery models)
BACKUP LOG
{ database_name | @database_name_var }
TO <backup_device> [ ,...n ]
[ <MIRROR TO clause> ] [ next-mirror-to ]
[ WITH { <general_WITH_options> | <log-specific_optionspec> } [ ,...n ] ]
[;]
<backup_device>::=
{
{ logical_device_name | @logical_device_name_var }
| { DISK
| TAPE
| URL } =
{ 'physical_device_name' | @physical_device_name_var | 'NUL' }
}
<MIRROR TO clause>::=
MIRROR TO <backup_device> [ ,...n ]
<file_or_filegroup>::=
{
FILE = { logical_file_name | @logical_file_name_var }
| FILEGROUP = { logical_filegroup_name | @logical_filegroup_name_var }
}
<read_only_filegroup>::=
FILEGROUP = { logical_filegroup_name | @logical_filegroup_name_var }
<general_WITH_options> [ ,...n ]::=
--Backup Set Options
COPY_ONLY
| { COMPRESSION | NO_COMPRESSION }
| DESCRIPTION = { 'text' | @text_variable }
| NAME = { backup_set_name | @backup_set_name_var }
| CREDENTIAL
| ENCRYPTION
| FILE_SNAPSHOT
| { EXPIREDATE = { 'date' | @date_var }
| RETAINDAYS = { days | @days_var } }
--Media Set Options
{ NOINIT | INIT }
| { NOSKIP | SKIP }
| { NOFORMAT | FORMAT }
| MEDIADESCRIPTION = { 'text' | @text_variable }
| MEDIANAME = { media_name | @media_name_variable }
| BLOCKSIZE = { blocksize | @blocksize_variable }
--Data Transfer Options
BUFFERCOUNT = { buffercount | @buffercount_variable }
| MAXTRANSFERSIZE = { maxtransfersize | @maxtransfersize_variable }
--Error Management Options
{ NO_CHECKSUM | CHECKSUM }
| { STOP_ON_ERROR | CONTINUE_AFTER_ERROR }
--Compatibility Options
RESTART
--Monitoring Options
STATS [ = percentage ]
--Tape Options
{ REWIND | NOREWIND }
| { UNLOAD | NOUNLOAD }
--Log-specific Options
{ NORECOVERY | STANDBY = undo_file_name }
| NO_TRUNCATE
--Encryption Options
ENCRYPTION (ALGORITHM = { AES_128 | AES_192 | AES_256 | TRIPLE_DES_3KEY } , encryptor_options ) <encryptor_options> ::=
SERVER CERTIFICATE = Encryptor_Name | SERVER ASYMMETRIC KEY = Encryptor_Name
这里是微软对于BACKUP语句的说明文档,因篇幅所限,这里只介绍几个选项参数的作用:
下面我们对数据库进行备份,并写入一个备份设备中:
USE ElecTravelCom;
GO
BACKUP DATABASE ElecTravelCom TO ElecTravelComBackupFile;
GO
运行结果如下(此时备份文件已经写入,因此备份设备也存在与磁盘上了):
前面说过,建立备份设备是创建永久备份文件,可以重复备份到同一个备份设备,现在我们创建临时备份文件,如下:
USE ElecTravelCom; --创建临时备份文件必须指定介质类型和完整的路径和文件名称;
GO
BACKUP DATABASE ElecTravelCom TO DISK = 'F:\MyBackupDataBase\Tmp\ElecTravelComBackupFile.bak';
GO
运行结果如下:
除了可以创建一个备份文件,SQL server可以向多个文件中写入备份数据,此时的备份称为并行备份.在执行并行备份时,数据库的数据就分散在这一个或多个文件中,这些文件组成一个备份集.
使用并行备份可以降低备份时间,例如一个备份文件备份数据库需要12小时,则两个备份文件也许只需6小时,三个也许只需4小时.
使用多个文件进行备份时,应考虑以下因素:
SQL server提供了四种不同的备份方法,以满足企业和数据库活动的需要,它们分别是:
完全备份数据库
、增量备份数据库
、事务日志备份
、数据库文件或文件组备份
完全备份数据库
: 备份数据库中的所有数据和结构.数据库的第一次备份应该要是完全备份,这种备份是其它备份的基础.使用完全备份数据库时,SQL server将备份发生在备份过程中的任何活动,备份事务日志中的任何内容,包括未提交的事务.根据本章开头的内容,我们知道完全备份数据库的语法如下(其下提及的各参数请参见本章开头部分):
--Backing Up a Whole Database
BACKUP DATABASE { database_name | @database_name_var }
TO <backup_device> [ ,...n ]
[ <MIRROR TO clause> ] [ next-mirror-to ]
[ WITH { DIFFERENTIAL
| <general_WITH_options> [ ,...n ] } ]
[;]
增量备份数据库
: 备份上一次完全数据库备份后改变的数据.可以降低数据库备份的时间.这种方法必须基于先完全备份数据库,且适用于经常变更的数据库,增量备份数据库的语法如下(其下提及的各参数请参见本章开头部分):
--Backing Up a Whole Database
BACKUP DATABASE { database_name | @database_name_var }
TO <backup_device> [ ,...n ]
[ <MIRROR TO clause> ] [ next-mirror-to ]
WITH DIFFERENTIAL
[;]
我们执行一次增量备份,如下:
USE ElecTravelCom;
GO
BACKUP DATABASE ElecTravelCom TO DISK = 'F:\MyBackupDataBase\Tmp\ElecTravelComBackupFile.bak'
WITH DIFFERENTIAL;
GO
运行结果如下:
事务日志备份
: 备份数据库中事务日志发生变化的过程.当执行完全备份数据库后,可以执行事务日志备份.使用事务日志备份时,应考虑如下因素:
事务日志备份的语法如下(其下提及的各参数请参见本章开头部分):
--Backing Up the Transaction Log (full and bulk-logged recovery models)
BACKUP LOG
{ database_name | @database_name_var }
TO <backup_device> [ ,...n ]
[ <MIRROR TO clause> ] [ next-mirror-to ]
[ WITH { <general_WITH_options> | <log-specific_optionspec> } [ ,...n ] ]
[;]
下面对AdventureWorks2017
进行一次完全数据库备份,再进行事务日志备份:
首先将AdventureWorks2017
的恢复模式由简单
改到完整
:
然后创建两个永久备份设备,进行备份:
USE AdventureWorks2017;
GO
EXEC sp_addumpdevice 'DISK','AdventureWorks2017BackupFile','F:\MyBackupDataBase\AdventureWorks2017\AdventureWorks2017BackupFile.bak';
EXEC sp_addumpdevice 'DISK','AdventureWorks2017BackupLogFile','F:\MyBackupDataBase\AdventureWorks2017\AdventureWorks2017BackupLogFile.bak';
GO
BACKUP DATABASE AdventureWorks2017 TO AdventureWorks2017BackupFile;
GO
BACKUP LOG AdventureWorks2017 TO AdventureWorks2017BackupLogFile;
GO
运行结果如下:
创建的备份文件如下:
再多说一句:事务日志备份时,可以使用TRUNCATE_ONLY、NO_LOG选项,它们的作用如下:
数据库文件或文件组备份
: 对于海量数据的大型数据库,可以指定若干个数据库文件/文件组进行备份,这种备份也需要先进行完全数据库备份.使用数据库文件或文件组备份时,应当指定数据库文件的逻辑名称或文件组的名称,且数据库文件或文件组应该进行周期性的备份,数据库文件或文件组备份的基本语法如下(其下提及的各参数请参见本章开头部分):
--Backing Up Specific Files or Filegroups
BACKUP DATABASE { database_name | @database_name_var }
<file_or_filegroup> [ ,...n ]
TO <backup_device> [ ,...n ]
[ <MIRROR TO clause> ] [ next-mirror-to ]
[ WITH { DIFFERENTIAL | <general_WITH_options> [ ,...n ] } ]
[;]
如下,将AdventureWorks2017
数据库的主数据文件AdventureWorks2017
做一个备份,备份到一个临时备份文件中:
USE AdventureWorks2017;
GO
BACKUP DATABASE AdventureWorks2017 FILE = 'AdventureWorks2017'
TO DISK = 'F:\MyBackupDataBase\Tmp\AdventureWorks2017.bak';
GO
运行结果如下:
还原是和备份相对应的操作,备份是为了防止意外发生,还原则是处理已经发生的意外.因此,备份是还原的基础,没有备份就谈不上还原,还原时备份的目的,备份是为了还原而备份,不是为了备份而备份.
还原是指将数据从备份中加载到系统的过程,在还原之前,应检查备份的安全性,这些安全性检查包括:
针对不同的数据库,应采用不同的还原方法.使用完全数据库备份还原时,系统将自动重建原来的数据库文件,并将这些文件放在备份数据库时这些文件所在的位置.这种进程是自动的,用户无需手动重建数据库.
在还原之前,应先验证备份文件是否有效,可以使用如下语句来验证备份的内容(点击语句获取详细信息):
如下,我们使用RESTORE VERIFYONLY语句验证备份:
USE ElecTravelCom;
GO
RESTORE VERIFYONLY FROM ElecTravelComBackupFile;
GO
备份集有效,结果如下:
使用RESTORE语句可以还原BACKUP创建的备份,下面是来自微软的文档:
--To Restore an Entire Database from a Full database backup (a Complete Restore):
RESTORE DATABASE { database_name | @database_name_var }
[ FROM <backup_device> [ ,...n ] ]
[ WITH
{
[ RECOVERY | NORECOVERY | STANDBY =
{standby_file_name | @standby_file_name_var }
]
| , <general_WITH_options> [ ,...n ]
| , <replication_WITH_option>
| , <change_data_capture_WITH_option>
| , <FILESTREAM_WITH_option>
| , <service_broker_WITH options>
| , <point_in_time_WITH_options-RESTORE_DATABASE>
} [ ,...n ]
]
[;]
--To perform the first step of the initial restore sequence of a piecemeal restore:
RESTORE DATABASE { database_name | @database_name_var }
<files_or_filegroups> [ ,...n ]
[ FROM <backup_device> [ ,...n ] ]
WITH
PARTIAL, NORECOVERY
[ , <general_WITH_options> [ ,...n ]
| , <point_in_time_WITH_options-RESTORE_DATABASE>
] [ ,...n ]
[;]
--To Restore Specific Files or Filegroups:
RESTORE DATABASE { database_name | @database_name_var }
<file_or_filegroup> [ ,...n ]
[ FROM <backup_device> [ ,...n ] ]
WITH
{
[ RECOVERY | NORECOVERY ]
[ , <general_WITH_options> [ ,...n ] ]
} [ ,...n ]
[;]
--To Restore Specific Pages:
RESTORE DATABASE { database_name | @database_name_var }
PAGE = 'file:page [ ,...n ]'
[ , <file_or_filegroups> ] [ ,...n ]
[ FROM <backup_device> [ ,...n ] ]
WITH
NORECOVERY
[ , <general_WITH_options> [ ,...n ] ]
[;]
--To Restore a Transaction Log:
RESTORE LOG { database_name | @database_name_var }
[ <file_or_filegroup_or_pages> [ ,...n ] ]
[ FROM <backup_device> [ ,...n ] ]
[ WITH
{
[ RECOVERY | NORECOVERY | STANDBY =
{standby_file_name | @standby_file_name_var }
]
| , <general_WITH_options> [ ,...n ]
| , <replication_WITH_option>
| , <point_in_time_WITH_options-RESTORE_LOG>
} [ ,...n ]
]
[;]
--To Revert a Database to a Database Snapshot:
RESTORE DATABASE { database_name | @database_name_var }
FROM DATABASE_SNAPSHOT = database_snapshot_name
<backup_device>::=
{
{ logical_backup_device_name |
@logical_backup_device_name_var }
| { DISK
| TAPE
| URL
} = { 'physical_backup_device_name' |
@physical_backup_device_name_var }
}
Note: URL is the format used to specify the location and the file name for the Microsoft Azure Blob. Although Microsoft Azure storage is a service, the implementation is similar to disk and tape to allow for a consistent and seamless restore experience for all the three devices.
<files_or_filegroups>::=
{
FILE = { logical_file_name_in_backup | @logical_file_name_in_backup_var }
| FILEGROUP = { logical_filegroup_name | @logical_filegroup_name_var }
| READ_WRITE_FILEGROUPS
}
<general_WITH_options> [ ,...n ]::=
--Restore Operation Options
MOVE 'logical_file_name_in_backup' TO 'operating_system_file_name'
[ ,...n ]
| REPLACE
| RESTART
| RESTRICTED_USER | CREDENTIAL
--Backup Set Options
| FILE = { backup_set_file_number | @backup_set_file_number }
| PASSWORD = { password | @password_variable }
--Media Set Options
| MEDIANAME = { media_name | @media_name_variable }
| MEDIAPASSWORD = { mediapassword | @mediapassword_variable }
| BLOCKSIZE = { blocksize | @blocksize_variable }
--Data Transfer Options
| BUFFERCOUNT = { buffercount | @buffercount_variable }
| MAXTRANSFERSIZE = { maxtransfersize | @maxtransfersize_variable }
--Error Management Options
| { CHECKSUM | NO_CHECKSUM }
| { STOP_ON_ERROR | CONTINUE_AFTER_ERROR }
--Monitoring Options
| STATS [ = percentage ]
--Tape Options.
| { REWIND | NOREWIND }
| { UNLOAD | NOUNLOAD }
<replication_WITH_option>::=
| KEEP_REPLICATION
<change_data_capture_WITH_option>::=
| KEEP_CDC
<FILESTREAM_WITH_option>::=
| FILESTREAM ( DIRECTORY_NAME = directory_name )
<service_broker_WITH_options>::=
| ENABLE_BROKER
| ERROR_BROKER_CONVERSATIONS
| NEW_BROKER
<point_in_time_WITH_options-RESTORE_DATABASE>::=
| {
STOPAT = { 'datetime'| @datetime_var }
| STOPATMARK = 'lsn:lsn_number'
[ AFTER 'datetime']
| STOPBEFOREMARK = 'lsn:lsn_number'
[ AFTER 'datetime']
}
<point_in_time_WITH_options-RESTORE_LOG>::=
| {
STOPAT = { 'datetime'| @datetime_var }
| STOPATMARK = { 'mark_name' | 'lsn:lsn_number' }
[ AFTER 'datetime']
| STOPBEFOREMARK = { 'mark_name' | 'lsn:lsn_number' }
[ AFTER 'datetime']
}
具体的参数信息可以看这里,本文只挑几个选项参数来说:
Human
,希望还原成Sales
,则需要指定该选项,备份和还原数据库名称一致则无需指定该选项.在执行还原操作时,必须指定RECOVERY | NORECOVERY中的一个,默认选项是RECOVERY,使用后数据库还原到正常状态:
如果有多个备份内容需要还原,则应该指定NORECOVERY选项,使用时应该注意:
如果数据库受到了损坏,此时需要对其进行还原操作.应该先从一个完整的备份中还原,这是所有还原的基础,此时应该指定RECOVERY选项.当进行一次完整还原时,以后的还原可以从多个备份内容还原,此时指定NORECOVERY选项.
如下是一个完整数据库还原操作:
USE master;
GO
RESTORE Database ElecTravelCom FROM ElecTravelComBackupFile WITH RECOVERY,REPLACE;
GO
运行结果如下:
上文指定了选项,注意如果不指定选项,就可能会提示没有备份日志文件尾部,此时如果确保日志文件中没有什么特别重要的内容,建议直接使用选项覆盖(还原本身就是回到之前的状态,自然不可能保留所有数据,因此建议直接覆盖),否则就会终止还原:
注意不可在进行还原操作时使用数据库,否则还原操作将会失败,如下图所示:
从增量备份中还原数据库,使用的语句与从完全备份中还原数据库完全相同.如果从增量备份中还原,系统会进行如下操作:
从事务日志备份中还原,可以使用RESTORE LOG语句,执行事务日志还原的起点可以是完全还原数据库、增量还原数据库或上一次事务日志还原数据库之后.下面进行一个事务日志还原操作:
USE master;
GO
RESTORE Database AdventureWorks2017 FROM AdventureWorks2017BackupFile WITH NORECOVERY,REPLACE;
GO
RESTORE LOG AdventureWorks2017 FROM AdventureWorks2017BackupFile WITH RECOVERY,REPLACE;
GO
运行结果如下:
另外可以使用STOPAT选项指定数据库的还原点(具体时间):
USE master;
GO
RESTORE DATABASE AdventureWorks2017 FROM AdventureWorks2017BackupFile WITH NORECOVERY;
RESTORE LOG AdventureWorks2017 FROM AdventureWorks2017BackupFile WITH NORECOVERY,REPLACE,
STOPAT = '04 14, 2019 9:30 AM';
RESTORE DATABASE AdventureWorks2017 WITH RECOVERY;
GO
运行结果如下:
关于RECOVERY和NORECOVERY选项,已经说过很多遍了,但是对于一些操作(如时间点还原)不管是否在最后指定RECOVERY,系统都不会将事务日志进行提交,这样是为了方便用户回滚之前的操作,数据库此时处于还原状态(不可用),但是一旦用户确定了这样的还原是正确的,不需要进行回滚操作,则可以将数据库手动置为可用状态,按照官方文档,我们可以这样写:
RESTORE DATABASE db_name FROM ... WITH NORECOVERY,...;
RESTORE LOG db_name FROM ... WITH NORECOVERY,...;
...
RESTORE DATABASE db_name WITH RECOVERY;
GO
即对所有的还原操作都指定NORECOVERY,直到最后确定所有的备份都还原完成,再用如下语句:
RESTORE DATABASE db_name WITH RECOVERY;
将数据库置为可用(已还原)状态,详情可以参考上面的一个时间点还原的例子.
上一篇: 存储过程、触发器和函数
下一篇: 事务