在SQL Server中出于数据安全的考虑,所以需要定期的备份数据库。而备份数据库一般又是在凌晨时间基本没有数据库操作的时候进行,所以我们不可能要求管理员每天守到晚上1点去备份数据库。要实现数据库的定时自动备份,最常用的方式就是使用SQL Server代理中的作业。启动SQL Server Agent服务,然后在其中新建作业,作业中添加1个备份步骤,类型是T-SQL脚本,然后在命令中输入如下SQL语句,该语句实现了对数据库TestDB1的完整备份,备份文件在C盘Backup文件夹中,文件名就是TestDB1+当时备份的日期字符串.bak。
set @name = ' C:\Backup\TestDB1_ ' +
convert ( varchar ( 50 ), getdate (), 112 ) + ' .bak '
BACKUP DATABASE [ TestDB1 ] TO
DISK = @name
WITH NOFORMAT, NOINIT,
NAME = N ' TestDB1-完整 数据库 备份 ' ,
SKIP, NOREWIND, NOUNLOAD
创建好步骤以后,接下来就是创建计划,创建计划的操作十分简单,界面上说明的很详细了,我就不多说了。另外还可以配置警报和通知,不过一般很少用这个。
使用SQL作业中执行SQL脚本进行备份的方法虽然已经很简单了,但是至少还是要去写BACKUP脚本,这点有些人觉得不爽,那有没有更简单,更懒的方法来实现数据库的自动定时备份呢?有,那就是“维护计划”。
“维护计划”是在SSMS的对象资源管理中“管理”节点下面。使用维护计划可以通过可视化的操作,只点点鼠标就可以创建数据库维护的SSIS包,然后仍然是通过SQL Server作业的方式来运行。维护计划与前面说到的备份方法本质的不同就是:维护计划是SSIS包,上面的是T-SQL脚本。
假设我们现在有一个生产系统的数据库需要进行备份,由于数据库中的数据很多,数据文件很大,如果每次都进行完整备份那么硬盘占用了很大空间,而且备份时间很长,维护起来也很麻烦。对此我们可以采用完整备份+差异备份的方式,每周日进行一次完整备份,每天晚上进行一次差异备份。使用差异备份可以减小备份文件的大小,同时还可以提高备份的速度,不过缺点就是必须使用上一次完整备份的文件和差异备份的文件才能还原差异备份时刻的数据库,单独只有差异备份文件是没有意义。
下面我来讲一下如何通过维护计划来实现完整备份+差异备份:
(1)在SSMS的对象资源管理器中右击“维护计划”,选择“维护计划向导”,系统将弹出向导窗口,如图:
这里向导已经告诉我们维护计划到底能够干什么了,其中最后一项“执行数据库备份”正是我们所需要的。
(2)点击“下一步”按钮,进入选择计划属性窗口,输入计划的名称,由于我们的计划包括2部分:完整备份和差异备份,这2部分的执行计划是不一样的,一个是一周执行一次,另一个是一天执行一次,所以要选择“每项任务单独计划”,如图:
(3)单击“下一步”按钮,选择维护任务,这里就是可以在维护计划中执行的任务,如果你想执行的任务在这里没有,那就还是不用维护计划来做,自己写SSIS包或者SQL语句吧。我们要执行的任务都在这里,选中这2个任务,如图:
(4)单击“下一步”进入选择维护任务顺序的界面,这里我们可以看到选中的任务出现在列表中,但是我们并不能调整其顺序,那是因为在步骤2中我们选择的是每项任务单独计划,所以这2个任务是独立的,没有先后顺序可言。如果当时选择的是另一个选项,那么这里就可以调整顺序了。
(5)选中“备份数据库(完整)”然后单击“下一步”按钮,系统将转到定义完整备份任务的界面,如图:
这个界面实在太长了,我把任务栏隐藏了都显示不完,出现了滚动条,这里我们选择要进行备份的数据库,选择为每个数据库创建备份文件,文件保存在C盘Backup目录下,扩展名是bak,出于安全起见,我们可以选中“验证备份完整性”,当然也可以不选。在SQL2008中提供了压缩备份的新特性,使得备份文件更小,备份速度更快,这里我们就是由压缩备份。最后是选择执行计划,我这里选的是每周日晚上0点的时候执行。
(6)单击“下一步”按钮,进入差异备份任务的设置界面,和上一步的界面是一样的,操作也是一样的,计划这里我们可以选择除了周日以外的每天进行差异备份,如图:
(7)单击“下一步”按钮,进入选择报告选项,这里我们可以将这个维护计划的执行报告写入文本文件中,也可以讲报告通过电子邮件发送给管理员。如果要发送邮件的话,那么需要配置SQL Server的数据库邮件,另外还要设置SQL Server代理中的操作员,关于邮件通知操作员的配置网上也讲的比较多,我这里就不详述了。
(8)单击“下一步”按钮,进入“完成该向导”的界面,系统列出了向导要完成的工作,如图:
(9)单击“完成”按钮,向导将创建对应的SSIS包和SQL作业:
(10)完成后,我们再刷新下对象资源管理器,我们可以看到对应的维护计划和该计划对应的作业:
现在维护计划是创建好了,急着想看看执行后的效果如何,不需要等到晚上12点去了,在“作业”下面,右击DbBackupPlan.Subplan_1,选择“作业开始步骤”系统便立即执行该作业,系统运行完成后,我们便可在C:\Backup文件夹下面有我们做的完整备份的备份文件。
以上的操作可以是纯粹的无键盘操作,不用写任何脚本,只需要点点鼠标即可。
这里需要注意的是,我们如果不是周日制定的该维护计划,那么制定该维护计划前一定要做个完整备份,而且该备份至少要保留到下周,不然到时候出了问题,发现只有这几个工作日的差异备份,而上一次的完整备份又被删了,那就郁闷了。
除了使用维护计划向导以外,我们还可以直接新建维护计划,也可以修改意见创建的维护计划。我们就以修改维护计划为例。对于前面创建好的完整备份+ 差异备份维护计划,现在我们需要每周对数据库备份进行一次清理,在完整备份完成后,要将1个月前的备份删除掉。那么我们只需要修改一下维护计划即可,具体操作如下:
(1)右击我们的维护计划,在弹出式菜单中选择“修改”选项,系统将新建一个选项卡来显示当前的维护计划。如图:
左下角是可用的维护计划组件,右下面板是维护计划的流程设置面板,其上面就是该计划的子计划列表。
(2)选中Subplan_1子计划,也就是每周完整备份的子计划,将“清除历史记录”任务从工具箱中拖拽到计划面板中,然后在面板中单击“备份数据库(完整)”组件,系统将显示一个绿色的箭头,将绿色箭头拖拽到“清除历史记录”组件上,如图:
也就是说在成功完整备份了数据库后,接下来才执行清除历史记录任务。
(3)右击“清除历史记录”任务,在弹出式菜单中选择“编辑”选项,系统将弹出清除历史记录任务设置窗口,如图:
这里既可以清除历史记录日志,也可以删除硬盘上的历史数据。这里我们要删除4周前的历史备份数据,单击“确定”回到计划面板,我们可以看到原本“清除历史记录”任务上的小红叉不见了。单击“保存”按钮,该计划便保存起来。(说明:我在SQL2008中文版虚拟机里面做的时候一旦修改维护计划,保存的时候就报错灾难性故障,不过我本机的英文版是正常的,不知道是我虚拟机的问题还是中文版的Bug,反正在英文版里面是对的。)
这样修改后,以后我们都不用手动去删除那些很久以前的数据库备份了,系统在执行完备份后就会删除那些满足条件的备份数据。
转载:http://www.cnblogs.com/zhangq723/archive/2012/03/13/2394102.html
--
-- 体现了SQL Server中的四个知识点:
--
-- 1. 获取SQL Server服务器上的默认目录
--
-- 2. 备份SQL语句的使用
--
-- 3. 恢复SQL语句的使用,同时考虑了强制恢复时关闭其他用户进程的处理
--
-- 4. 作业创建SQL语句的使用
/* 1.--得到数据库的文件目录
@dbname 指定要取得目录的数据库名
如果指定的数据不存在,返回安装SQL时设置的默认数据目录
如果指定NULL,则返回默认的SQL备份目录名
*/
/* --调用示例
select 数据库文件目录=dbo.f_getdbpath('tempdb')
,[默认SQL SERVER数据目录]=dbo.f_getdbpath('')
,[默认SQL SERVER备份目录]=dbo.f_getdbpath(null)
-- */
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[f_getdbpath] ' ) and xtype in (N ' FN ' , N ' IF ' , N ' TF ' ))
drop function [ dbo ] . [ f_getdbpath ]
GO
create function f_getdbpath( @dbname sysname)
returns nvarchar ( 260 )
as
begin
declare @re nvarchar ( 260 )
if @dbname is null or db_id ( @dbname ) is null
select @re = rtrim ( reverse (filename)) from master..sysdatabases where name = ' master '
else
select @re = rtrim ( reverse (filename)) from master..sysdatabases where name = @dbname
if @dbname is null
set @re = reverse ( substring ( @re , charindex ( ' \ ' , @re ) + 5 , 260 )) + ' BACKUP '
else
set @re = reverse ( substring ( @re , charindex ( ' \ ' , @re ), 260 ))
return ( @re )
end
go
/* 2.--备份数据库
*/
/* --调用示例
--备份当前数据库
exec p_backupdb @bkpath='c:\',@bkfname='db_\DATE\_db.bak'
--差异备份当前数据库
exec p_backupdb @bkpath='c:\',@bkfname='db_\DATE\_df.bak',@bktype='DF'
--备份当前数据库日志
exec p_backupdb @bkpath='c:\',@bkfname='db_\DATE\_log.bak',@bktype='LOG'
-- */
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[p_backupdb] ' ) and OBJECTPROPERTY (id, N ' IsProcedure ' ) = 1 )
drop procedure [ dbo ] . [ p_backupdb ]
GO
create proc p_backupdb
@dbname sysname = '' , -- 要备份的数据库名称,不指定则备份当前数据库
@bkpath nvarchar ( 260 ) = '' , -- 备份文件的存放目录,不指定则使用SQL默认的备份目录
@bkfname nvarchar ( 260 ) = '' , -- 备份文件名,文件名中可以用\DBNAME\代表数据库名,\DATE\代表日期,\TIME\代表时间
@bktype nvarchar ( 10 ) = ' DB ' , -- 备份类型:'DB'备份数据库,'DF' 差异备份,'LOG' 日志备份
@appendfile bit = 1 -- 追加/覆盖备份文件
as
declare @sql varchar ( 8000 )
if isnull ( @dbname , '' ) = '' set @dbname = db_name ()
if isnull ( @bkpath , '' ) = '' set @bkpath = dbo.f_getdbpath( null )
if isnull ( @bkfname , '' ) = '' set @bkfname = ' \DBNAME\_\DATE\_\TIME\.BAK '
set @bkfname = replace ( replace ( replace ( @bkfname , ' \DBNAME\ ' , @dbname )
, ' \DATE\ ' , convert ( varchar , getdate (), 112 ))
, ' \TIME\ ' , replace ( convert ( varchar , getdate (), 108 ), ' : ' , '' ))
set @sql = ' backup ' + case @bktype when ' LOG ' then ' log ' else ' database ' end + @dbname
+ ' to disk= ''' + @bkpath + @bkfname
+ ''' with ' + case @bktype when ' DF ' then ' DIFFERENTIAL, ' else '' end
+ case @appendfile when 1 then ' NOINIT ' else ' INIT ' end
print @sql
exec ( @sql )
go
/* 3.--恢复数据库
*/
/* --调用示例
--完整恢复数据库
exec p_RestoreDb @bkfile='c:\db_20031015_db.bak',@dbname='db'
--差异备份恢复
exec p_RestoreDb @bkfile='c:\db_20031015_db.bak',@dbname='db',@retype='DBNOR'
exec p_backupdb @bkfile='c:\db_20031015_df.bak',@dbname='db',@retype='DF'
--日志备份恢复
exec p_RestoreDb @bkfile='c:\db_20031015_db.bak',@dbname='db',@retype='DBNOR'
exec p_backupdb @bkfile='c:\db_20031015_log.bak',@dbname='db',@retype='LOG'
-- */
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[p_RestoreDb] ' ) and OBJECTPROPERTY (id, N ' IsProcedure ' ) = 1 )
drop procedure [ dbo ] . [ p_RestoreDb ]
GO
create proc p_RestoreDb
@bkfile nvarchar ( 1000 ), -- 定义要恢复的备份文件名
@dbname sysname = '' , -- 定义恢复后的数据库名,默认为备份的文件名
@dbpath nvarchar ( 260 ) = '' , -- 恢复后的数据库存放目录,不指定则为SQL的默认数据目录
@retype nvarchar ( 10 ) = ' DB ' , -- 恢复类型:'DB'完事恢复数据库,'DBNOR' 为差异恢复,日志恢复进行完整恢复,'DF' 差异备份的恢复,'LOG' 日志恢复
@filenumber int = 1 , -- 恢复的文件号
@overexist bit = 1 , -- 是否覆盖已经存在的数据库,仅@retype为
@killuser bit = 1 -- 是否关闭用户使用进程,仅@overexist=1时有效
as
declare @sql varchar ( 8000 )
-- 得到恢复后的数据库名
if isnull ( @dbname , '' ) = ''
select @sql = reverse ( @bkfile )
, @sql = case when charindex ( ' . ' , @sql ) = 0 then @sql
else substring ( @sql , charindex ( ' . ' , @sql ) + 1 , 1000 ) end
, @sql = case when charindex ( ' \ ' , @sql ) = 0 then @sql
else left ( @sql , charindex ( ' \ ' , @sql ) - 1 ) end
, @dbname = reverse ( @sql )
-- 得到恢复后的数据库存放目录
if isnull ( @dbpath , '' ) = '' set @dbpath = dbo.f_getdbpath( '' )
-- 生成数据库恢复语句
set @sql = ' restore ' + case @retype when ' LOG ' then ' log ' else ' database ' end + @dbname
+ ' from disk= ''' + @bkfile + ''''
+ ' with file= ' + cast ( @filenumber as varchar )
+ case when @overexist = 1 and @retype in ( ' DB ' , ' DBNOR ' ) then ' ,replace ' else '' end
+ case @retype when ' DBNOR ' then ' ,NORECOVERY ' else ' ,RECOVERY ' end
print @sql
-- 添加移动逻辑文件的处理
if @retype = ' DB ' or @retype = ' DBNOR '
begin
-- 从备份文件中获取逻辑文件名
declare @lfn nvarchar ( 128 ), @tp char ( 1 ), @i int
-- 创建临时表,保存获取的信息
create table #tb(ln nvarchar ( 128 ),pn nvarchar ( 260 ),tp char ( 1 ),fgn nvarchar ( 128 ),sz numeric( 20 , 0 ),Msz numeric( 20 , 0 ))
-- 从备份文件中获取信息
insert into #tb exec ( ' restore filelistonly from disk= ''' + @bkfile + '''' )
declare #f cursor for select ln,tp from #tb
open #f
fetch next from #f into @lfn , @tp
set @i = 0
while @@fetch_status = 0
begin
select @sql = @sql + ' ,move ''' + @lfn + ''' to ''' + @dbpath + @dbname + cast ( @i as varchar )
+ case @tp when ' D ' then ' .mdf ''' else ' .ldf ''' end
, @i = @i + 1
fetch next from #f into @lfn , @tp
end
close #f
deallocate #f
end
-- 关闭用户进程处理
if @overexist = 1 and @killuser = 1
begin
declare @spid varchar ( 20 )
declare #spid cursor for
select spid = cast (spid as varchar ( 20 )) from master..sysprocesses where dbid = db_id ( @dbname )
open #spid
fetch next from #spid into @spid
while @@fetch_status = 0
begin
exec ( ' kill ' + @spid )
fetch next from #spid into @spid
end
close #spid
deallocate #spid
end
-- 恢复数据库
exec ( @sql )
go
/* 4.--创建作业
*/
/* --调用示例
--每月执行的作业
exec p_createjob @jobname='mm',@sql='select * from syscolumns',@freqtype='month'
--每周执行的作业
exec p_createjob @jobname='ww',@sql='select * from syscolumns',@freqtype='week'
--每日执行的作业
exec p_createjob @jobname='a',@sql='select * from syscolumns'
--每日执行的作业,每天隔4小时重复的作业
exec p_createjob @jobname='b',@sql='select * from syscolumns',@fsinterval=4
-- */
if exists ( select * from dbo.sysobjects where id = object_id (N ' [dbo].[p_createjob] ' ) and OBJECTPROPERTY (id, N ' IsProcedure ' ) = 1 )
drop procedure [ dbo ] . [ p_createjob ]
GO
create proc p_createjob
@jobname varchar ( 100 ), -- 作业名称
@sql varchar ( 8000 ), -- 要执行的命令
@dbname sysname = '' , -- 默认为当前的数据库名
@freqtype varchar ( 6 ) = ' day ' , -- 时间周期,month 月,week 周,day 日
@fsinterval int = 1 , -- 相对于每日的重复次数
@time int = 170000 -- 开始执行时间,对于重复执行的作业,将从0点到23:59分
as
if isnull ( @dbname , '' ) = '' set @dbname = db_name ()
-- 创建作业
exec msdb..sp_add_job @job_name = @jobname
-- 创建作业步骤
exec msdb..sp_add_jobstep @job_name = @jobname ,
@step_name = ' 数据处理 ' ,
@subsystem = ' TSQL ' ,
@database_name = @dbname ,
@command = @sql ,
@retry_attempts = 5 , -- 重试次数
@retry_interval = 5 -- 重试间隔
-- 创建调度
declare @ftype int , @fstype int , @ffactor int
select @ftype = case @freqtype when ' day ' then 4
when ' week ' then 8
when ' month ' then 16 end
, @fstype = case @fsinterval when 1 then 0 else 8 end
if @fsinterval <> 1 set @time = 0
set @ffactor = case @freqtype when ' day ' then 0 else 1 end
EXEC msdb..sp_add_jobschedule @job_name = @jobname ,
@name = ' 时间安排 ' ,
@freq_type = @ftype , -- 每天,8 每周,16 每月
@freq_interval = 1 , -- 重复执行次数
@freq_subday_type = @fstype , -- 是否重复执行
@freq_subday_interval = @fsinterval , -- 重复周期
@freq_recurrence_factor = @ffactor ,
@active_start_time = @time -- 下午17:00:00分执行
go
/* --应用案例--备份方案:
完整备份(每个星期天一次)+差异备份(每天备份一次)+日志备份(每2小时备份一次)
调用上面的存储过程来实现
-- */
declare @sql varchar ( 8000 )
-- 完整备份(每个星期天一次)
set @sql = ' exec p_backupdb @dbname= '' 要备份的数据库名 '''
exec p_createjob @jobname = ' 每周备份 ' , @sql , @freqtype = ' week '
-- 差异备份(每天备份一次)
set @sql = ' exec p_backupdb @dbname= '' 要备份的数据库名 '' ,@bktype= ' DF ''
exec p_createjob @jobname = ' 每天差异备份 ' , @sql , @freqtype = ' day '
-- 日志备份(每2小时备份一次)
set @sql = ' exec p_backupdb @dbname= '' 要备份的数据库名 '' ,@bktype= ' LOG ''
exec p_createjob @jobname = ' 每2小时日志备份 ' , @sql , @freqtype = ' day ' , @fsinterval = 2
/* --应用案例2
生产数据核心库:PRODUCE
备份方案如下:
1.设置三个作业,分别对PRODUCE库进行每日备份,每周备份,每月备份
2.新建三个新库,分别命名为:每日备份,每周备份,每月备份
3.建立三个作业,分别把三个备份库还原到以上的三个新库。
目的:当用户在produce库中有任何的数据丢失时,均可以从上面的三个备份库中导入相应的TABLE数据。
-- */
declare @sql varchar ( 8000 )
-- 1.建立每月备份和生成月备份数据库的作业,每月每1天下午16:40分进行:
set @sql = '
declare @path nvarchar(260),@fname nvarchar(100)
set @fname= '' PRODUCE_ '' +convert(varchar(10),getdate(),112)+ '' _m.bak ''
set @path=dbo.f_getdbpath(null)+@fname
--备份
exec p_backupdb @dbname= '' PRODUCE '' ,@bkfname=@fname
--根据备份生成每月新库
exec p_RestoreDb @bkfile=@path,@dbname= '' PRODUCE_月 ''
--为周数据库恢复准备基础数据库
exec p_RestoreDb @bkfile=@path,@dbname= '' PRODUCE_周 '' ,@retype= '' DBNOR ''
--为日数据库恢复准备基础数据库
exec p_RestoreDb @bkfile=@path,@dbname= '' PRODUCE_日 '' ,@retype= '' DBNOR ''
'
exec p_createjob @jobname = ' 每月备份 ' , @sql , @freqtype = ' month ' , @time = 164000
-- 2.建立每周差异备份和生成周备份数据库的作业,每周日下午17:00分进行:
set @sql = '
declare @path nvarchar(260),@fname nvarchar(100)
set @fname= '' PRODUCE_ '' +convert(varchar(10),getdate(),112)+ '' _w.bak ''
set @path=dbo.f_getdbpath(null)+@fname
--差异备份
exec p_backupdb @dbname= '' PRODUCE '' ,@bkfname=@fname,@bktype= '' DF ''
--差异恢复周数据库
exec p_backupdb @bkfile=@path,@dbname= '' PRODUCE_周 '' ,@retype= '' DF ''
'
exec p_createjob @jobname = ' 每周差异备份 ' , @sql , @freqtype = ' week ' , @time = 170000
-- 3.建立每日日志备份和生成日备份数据库的作业,每周日下午17:15分进行:
set @sql = '
declare @path nvarchar(260),@fname nvarchar(100)
set @fname= '' PRODUCE_ '' +convert(varchar(10),getdate(),112)+ '' _l.bak ''
set @path=dbo.f_getdbpath(null)+@fname
--日志备份
exec p_backupdb @dbname= '' PRODUCE '' ,@bkfname=@fname,@bktype= '' LOG ''
--日志恢复日数据库
exec p_backupdb @bkfile=@path,@dbname= '' PRODUCE_日 '' ,@retype= '' LOG ''
'
exec p_createjob @jobname = ' 每周差异备份 ' , @sql , @freqtype = ' day ' , @time = 171500