数据库定期自动备份到远程服务器

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Rulition/archive/2009/10/17/4688982.aspx

/*
THIS4.0 数据库备份脚本

[作者] Rulition QQ:7355157
       2010年5月21日15:35:13 完成
       2010年5月24日11:35:13 细节修改
       2010年5月25日11:31:13 增加[完整备份]前的一致性检查
       2010年5月27日10:31:13 检查差异备份的大小,避免过大文件影响差异备份.
       2010年5月28日11:14:15 补备份时查看最近是否已做过完全备份.

[版本] v1.5
[环境] SQL2000 和 SQL2005 中测试通过

[说明]
利用双机热备的磁盘空间,将 THIS4.0 数据库的备份计划设置为以下方式:

"差异备份"-每N小时执行一次,分别存储到 1# 和 2# 的 D:\This_BackUp , 保留3天。
"完整备份"-晚上 00:30 和 12:30 及 17:30 各执行一次,存储到 z$\This_BackUp,保留15天。

[特点]
1)备份频度由 SQL 计划任务来调节
2)操作日志由 SQL 计划任务来收集 (详见计划任务的高级选项)
3) 先删除过期备份文件,然后再执行备份操作,与 SQL 操作模式相反
  (也可以修改 (备份前的准备工作) 这一小节,与 SQL 操作模式一样。)
4)自动判断并建立备份文件夹、按保留时间删除过期备份文件
5)在执行备份操作前,自动检查空间是否够用,自动回避[差异备份][完整备份]同时进行,并进行一致性检查。
6)检查差异备份的大小,避免过大文件影响差异备份.并自动做一次[完整备份]

[注意]
1)脚本中大量使用 MS-DOS 命令,如果不是很熟悉,请不要修改!
2)为删除过期备份文件使用了 FORFILES.exe 命令,必须注明具体路径,否则无法执行。
   这个可以在 Win2000 环境下使用的命令,是 FORFILES v 1.1 - emmanubo@microsoft.com - 4/98
   与 Win7 系统自带的中文版,在使用参数上有一点区别,使用时请注意!
3)为减少操作日志大小,在 (一致性检查) 这一小节调用了 isql.exe ,这个文件在 SQL2005 中没有,
   可以从 SQL2000 系统中拷贝过来,使用时注意路径。

[参考]
1)清理系统备份日志、 删除备份作业的历史记录
2)关于SQL2005 远程备份

*以上资料详见脚本最后一部分


exec usp_job_backup_this4

*/

CREATE Proc usp_job_backup_this4
(@Is_Run int = 0 ) ---- 当 @Is_Run = 1 时,自动执行所有操作,否则,显示操作记录。
AS

----
SET NOCOUNT ON
----
Select GetDate() AS '【开始时间】'
----Test
----Declare @Is_Run int
----Select @Is_Run = 0
----
/*参数设置*/
Declare @数据库名 varchar(100)
Declare @备份路径 varchar(100)
Declare @备份文件 varchar(100)
Declare @备份方式 varchar(10)
Declare @保留时间 varchar(10)
Declare @备份语句 varchar(1000)
----初值设置
Select @数据库名 = 'THIS4'
Select @备份文件 = Convert(char(8),getdate(),112) + replace(convert(char(6),getdate(),108),':','')
----
/*完整备份-参数设置*/
If Convert(varchar,getdate(),24) between '03:00:00' and '04:00:00'
or Convert(varchar,getdate(),24) between '12:00:00' and '13:00:00'
---or Convert(varchar,getdate(),24) between '17:00:00' and '18:00:00'
Begin
Select @备份方式 = '完整备份'
Select @备份路径 = '\\202.202.202.26\Z$\This_BackUp'
Select @备份文件 = @备份文件+'.bak'
Select @保留时间 = '10'
Print '【操作方式】' + '★' + @备份方式 + '★'
End
/*差异备份-参数设置*/
Else
Begin
Select @备份方式 = '差异备份'
Declare @备份路径1 varchar(100)
Declare @备份路径2 varchar(100)
Select @备份路径1 = '\\202.202.202.22\D$\This_BackUp'
Select @备份路径2 = '\\202.202.202.23\D$\This_BackUp'
Select @备份文件   = @备份文件+'.dif'
Select @保留时间 = '3'
Print '【操作方式】' + '★' + @备份方式 + '★'
End
----
/*提取上次备份的数据*/
Declare @backup_set_id int ----备份操作的ID号
Declare @backup_size   numeric ----备份文件大小,其结果/1024才能与电脑看到的一致[单位:KB]
Declare @description   nvarchar(510) ----备份描述
Declare @name        nvarchar(256) ----备份名称,后面跟上'_KB'+当时备份时的库文件大小[单位:KB]
Select top 1 @backup_set_id = backup_set_id , @backup_size = isnull(backup_size/1024,1) ,
      @description = [description] ,   @name = [name]
  from msdb.dbo.backupset (NOLOCK)
where type = case when @备份方式 = '差异备份' then 'I' else 'D' end
   and database_name = @数据库名
order by backup_set_id DESC
----
If @备份方式 = '差异备份'
Begin
---切换@备份路径
if @description = @备份路径1+'\'+@数据库名 Select @备份路径 = @备份路径2
if @description = @备份路径2+'\'+@数据库名 Select @备份路径 = @备份路径2
Print '【上次备份】' + @description
End
----
/*显示操作信息*/
Print '【本次备份】' + @备份路径 + '\' + @数据库名
----
/*参数检查*/
----
Declare @SQL nvarchar(4000)
---------------------------------------------------------------------------------------------
----判断@数据库名
if @数据库名=''
    Begin
        Print('Error:请指定需要备份的数据库')
        Return
    End
----判断@数据库名是否存在
Select @SQL = '
if not exists ( select name from master.dbo.sysdatabases where name=''' + @数据库名 + ''' )
Begin
        Print(''Error:指定的数据库名无效,如有必要请注意大小写!或运行 sp_helpsort 检查 SQL Server 排序次序和字符集'')
        Return
End
'
Exec (@SQL)
---------------------------------------------------------------------------------------------
----判断@备份路径
if isnull(@备份路径,'')=''
    Begin
        Print('Error:请指定备份路径!例如: E:\data.bak')
        Return
  End
/*开启 xp_cmdshell 支持*/
Exec sp_configure 'show advanced options', 1
reconfigure with override
Exec sp_configure 'xp_cmdshell', 1
reconfigure with override
Exec sp_configure 'show advanced options', 0
reconfigure with override
----判断自动建立相应文件夹
Select @SQL = ' if not exist ' + @备份路径 +'\'+@数据库名 + '\*.* md '+ @备份路径 +'\'+@数据库名 + '''' + ' NO_OUTPUT '
Declare @result int
   Exec @result = xp_cmdshell @SQL , NO_OUTPUT
if (@result = 1)
Begin
Print('Error:指定的备份路径无法使用!(有可能是访问权限的问题)'+ @备份路径 )
Return
End
---------------------------------------------------------------------------------------------
----判断@备份文件
if ISNULL(@备份文件,1) = '1'
Begin
Print('Error:在获取[@备份文件]时出现错误!'+ @备份文件 )
Return
End
/*备份前的准备工作*/
---------------------------------------------------------------------------------------------
----(10)获取@备份路径所在分区的剩余空间大小[已换成KB,近似值= 可用字节/1024*0.95 ]
Select @SQL=' dir '+ @备份路径 + ' | find "可用字节" > "%temp%\Rulition" '
  Exec xp_cmdshell @SQL , NO_OUTPUT
  Exec xp_cmdshell ' for /f "tokens=3 delims= " %i in (%temp%\Rulition) do @echo %i > "%temp%\Rulition" ' , NO_OUTPUT
Select @SQL=' for /f "tokens=1-9 delims=," %1 in (%temp%\Rulition) do @echo %1%2%3%4%5%6%7%8%9 '
----将结果传入到表[必须充许空值插入,否则会出错!]
Create Table #disk_space (free_sizes VarChar(100) NULL )
Insert into  #disk_space Exec xp_cmdshell @SQL
Delete from  #disk_space where free_sizes is null
----提取结果
Declare @disk_space numeric
Select @disk_space = Convert(numeric,free_sizes)/1024*0.95 from #disk_space
   Drop table #disk_space
---------------------------------------------------------------------------------------------
----(20)获取当前数据库大小(参考:sp_spaceused)[已换成KB,近似值= 统计结果/1024*0.95 ]
Select @SQL = ' Declare @dbsize  bigint ' + CHAR(10) +
      ' Declare @logsize bigint ' + CHAR(10) +
      ' Declare @database_size bigint ' + CHAR(10) +
' Select @dbsize  = sum(convert(bigint,case when status & 64 = 0 then size else 0 end)) ,'+ CHAR(10) +
'        @logsize = sum(convert(bigint,case when status & 64 <> 0 then size else 0 end))' + CHAR(10) +
' from ' + @数据库名 + '.dbo.sysfiles ' + CHAR(10) +
' Select (convert (dec (15,2),@dbsize) + convert (dec (15,2),@logsize) ) * 8192 '
----将结果传入到表
Create Table #database_size (files_sizes dec(15,2) NULL )
Insert into  #database_size Exec (@SQL)
----提取结果
Declare @database_size numeric
Select @database_size = Convert(numeric,files_sizes)/1024*0.95 from #database_size
   Drop table #database_size
---------------------------------------------------------------------------------------------
----(25)一致性检查
/*如果一致性检查在白天进行时要花费很长时间,可以设置为只在晚上处理。(具体情况详见操作结果日志)*/
If @备份方式 = '完整备份'
Begin
/*
在数据库备份之前,应该进行数据的一致性检查:  
     1。运行检查点进程 checkpoint  [强制将当前数据库的所有脏页写到磁盘上。]
     2。检查数据库 dbcc checkdb  
     3。检查页面 dbcc checkalloc  
     4。检查系统表 dbcc checkcatalog  
然后再进行数据库备份。
----
【DBCC CHECKDB】 是大量占用 CPU 和磁盘的操作。每一个需要检查的数据页都必须首先从磁盘读入内存。
另外,DBCC CHECKDB 使用 tempdb 排序。建议在服务器负荷较少的时候运行 DBCC CHECKDB。
如果在负荷高峰期运行 DBCC CHECKDB,那么事务吞吐量性能和 DBCC CHECKDB 完成时间性能都会受到影响。
----
【DBCC CHECKALLOC】 对数据库中的分配和页使用(包括索引视图)情况进行检查。
只用于向后兼容性的 NOINDEX 选项也适用于索引视图。
如果已经执行 DBCC CHECKDB,则不必执行 DBCC CHECKALLOC。
DBCC CHECKDB 是 DBCC CHECKALLOC 的超集,除了对索引结构和数据完整性进行检查之外,它还包括对分配进行检查。
*/
----★一致性检查[只保留检查的最终结果到日志文件,注意修改 isql.exe 使用的用户名和密码还有 isql.exe 所在的路径]★
Print '【一致性检查】'
Declare @CHECK VarChar(1000)
----
Print '1.运行检查点进程 (' + Convert(varchar,GetDate(),21) + ')'
if (@Is_Run = 1) CHECKPOINT
----
Print '2.检查数据库 (' + Convert(varchar,GetDate(),21) + ')'
Select @CHECK = 'D:\isql.exe -S '+ @@SERVERNAME + ' -d '+ @数据库名 + ' -U sa -P SERVER -Q "dbcc checkdb (' + @数据库名 + ') " -o "%temp%\check_db.log" -w 9999 & find "CHECKDB" "%temp%\check_db.log" '
if (@Is_Run = 0) Print @CHECK
if (@Is_Run = 1) EXEC xp_cmdshell @CHECK
----
Print '3.检查页面 (' + Convert(varchar,GetDate(),21) + ')'
Select @CHECK = 'D:\isql.exe -S '+@@SERVERNAME + ' -d '+ @数据库名 + ' -U sa -P SERVER -Q "dbcc checkalloc (' + @数据库名 + ') " -o "%temp%\check.log" -w 9999 & find "CHECKALLOC" "%temp%\check.log" '
if (@Is_Run = 0) Print @CHECK
if (@Is_Run = 1) EXEC xp_cmdshell @CHECK
----
Print '4.检查系统表 (' + Convert(varchar,GetDate(),21) + ')'
Select @CHECK = 'C:\Progra~1\7-Zip\isql.exe -S ' + @@SERVERNAME + ' -d ' + @数据库名 + ' -U sa -P SERVER -Q "dbcc checkcatalog (' + @数据库名 + ')" '
if (@Is_Run = 0) Print @CHECK
if (@Is_Run = 1) EXEC xp_cmdshell @CHECK
----
Print '5.一致性检查已完成 (' + Convert(varchar,GetDate(),21) + ')'
End
---------------------------------------------------------------------------------------------
----(30)删除过期备份文件
----   凡大于(@保留时间)24小时的都会被删除,注意扩展名!!
----   forfiles.exe 也要指定路径,否则无法执行这个操作.
Declare @删除操作 nvarchar(4000)
----
Select  @删除操作 =' pushd ' + @备份路径 + '\' + @数据库名 + ' && ' +
' d:\forfiles.exe -M'+@数据库名+'_*.bak -c"cmd /c echo 删除 @FILE & del @FILE " -D-'+ @保留时间 + ' && ' +
' d:\forfiles.exe -M'+@数据库名+'_*.dif -c"cmd /c echo 删除 @FILE & del @FILE " -D-'+ @保留时间 + ' && ' +
' popd '
Print '【删除文件】 保留时间: ' + @保留时间 + ' 天'
  if (@Is_Run = 0) Print @删除操作
  Exec xp_cmdshell @删除操作---- , no_output
---------------------------------------------------------------------------------------------
----(40)备份可行性估算
----  如果 [剩余空间] 不够存放 [预期备份]的大小,先删除过期备份文件,如果还不够用,则退出。
----       [预期备份的大小] = [上次备份文件的大小] / [上次备份时数据库的大小] * [当前数据库的大小]
----       SQL的备份策略是先备份后删除,事先也不判断一下,很浪费时间。
----
----[上次备份时数据库的大小]取自 msdb.dbo.backupset.name ,在生成备份语句时进行标记。
----
Declare @last_data_sizes numeric
Declare @评估结果 varchar(8)
----
Select @last_data_sizes = 1
Select @评估结果 = '通过'
----如果上次备份时没有'_KB'标记,则默认为1。
if ( CharIndex('_KB',@name) = 0 )  Select @last_data_sizes = 1
    else
Begin
----如果仅有'_KB'标记,但没有数据,也默认为1。
if ( CharIndex('_KB',@name) + 3 ) > LEN(@name) Select @last_data_sizes = 1
----否则,提取'_KB'后的数据
else Select @last_data_sizes = Convert(numeric,SubString(@name,CharIndex('_KB',@name)+3,20))
End
----评估情况明细
if (@Is_Run = 0)
Begin
Print '【评估情况】'
Select @backup_set_id as   '上次备份的ID: '
Select isnull(@backup_size,1) as '上次备份文件的大小(KB)' , isnull(@last_data_sizes,1) as '上次备份时数据库的大小(KB)'
Select @database_size as '当前数据库的大小(KB)' , @disk_space as '可用磁盘空间(KB)'
Print '【本次备份】' + @备份路径 + '\'+ @数据库名
End
----开始评估
----如果[上次备份文件的大小] = 1 , 则比较 [当前数据库的大小]*0.80 与 [可用磁盘空间]
----这里的 (*0.80) 是人个经验值,可以结合每次的【评估情况】大致算出来.
if @last_data_sizes = 1
Begin
if @database_size * 0.80 > @disk_space
Begin
Select @备份路径 + ' 可用磁盘空间不足,无法存入数据库备份文件,退出操作!' + CHAR(10) as '【错误提示1】'
Return
End
End
----[预期备份的大小] = [上次备份文件的大小] / [上次备份时数据库的大小] * [当前数据库的大小]
else
Begin
if ( @backup_size / @last_data_sizes ) * @database_size  > @disk_space
Begin
Select @备份路径 + ' 可用磁盘空间不足,无法存入数据库备份文件,退出操作!' + CHAR(10) as '【错误提示2】'
Return
End
End
----检查差异备份的大小
----如果 [上次备份文件的大小] 相对 [当前数据库的大小] 超过 30% ,说明上次的完全备份失败了,与此同时,最近又没有做过完整备份,
----则必须再次进行完整备份,否则,数量过多的大体积差异备份文件会占用对应的磁盘空间,造成差异备份的失败.
----这里的 (超过 30%) 是人个经验值,可以结合每次的【评估情况】大致算出来.
If(  @备份方式 = '差异备份' and ( @last_data_sizes <> 1 ) )
Begin
if (isnull(@backup_size,1) / @database_size > 0.3)
   if NOT EXISTS (Select 1 from msdb.dbo.backupset where type = 'D' and backup_set_id > @backup_set_id and [name] like '%' + @数据库名 + '%' )
Begin
Print  '【有情提示】' +  '上次(差异备份)的文件偏大,有可能最近一次的完整备份失败!现在改为【完整备份】进行补救。'
Print  '【有情提示】' +  '如果多次出现这个问题,请检查相关所有操作或设置。'
Select @备份方式 = '完整备份'
Select @评估结果 = '失败'
Select @备份文件 = Replace(@备份文件,'.dif','.BBF') ----将后缀名改为:.BBF (补备份)
End
End
----
if @评估结果 = '通过' Print '【评估通过,可以备份!】'
---------------------------------------------------------------------------------------------
/*组织@备份语句*/
Select @备份语句=''
Select @备份语句='BACKUP DATABASE '+ @数据库名 + ' TO DISK = N''' + @备份路径+'\'+@数据库名+'\'+ @数据库名 + '_' +@备份文件 +
''' WITH RETAINDAYS = ' + @保留时间 + ', NOFORMAT, NOINIT, NAME = N''' +
@数据库名 + '_' + @备份方式 + '_' + @备份文件 +'_KB' + Convert(varchar,@database_size) +
''', SKIP, NOREWIND, NOUNLOAD, STATS = 100,'
+ ' DESCRIPTION = '''+ @备份路径 + '\' + @数据库名 +''''
----
    If @备份方式 = '差异备份' Select @备份语句 = @备份语句 + ' , DIFFERENTIAL '
----
/*显示@备份语句*/
Print '【备份语句】'
Print @备份语句
----
/*[差异备份]回避[完整备份]*/
if exists(select spid from  master.dbo.sysprocesses where db_name(dbid) = @数据库名
             and status = 'runnable' and cmd= 'BACKUP DATABASE')
Begin
Print @数据库名 + ' 正在备份,跳过本次操作!'+ CHAR(10)
Return
End
----
/*执行操作*/
if (@Is_Run = 1) Exec (@备份语句)
----
Select GetDate() AS '【结束时间】'
----
/*
[参考资料1]
----清理日志记录
Select * from msdb.dbo.backupset
Select * from msdb.dbo.restorehistory
----
删除备份和还原历史记录表中所有早于指定日期的备份集的条目。
由于执行备份或还原操作后会在备份和还原历史记录表中添加一些行,
因此使用 sp_delete_backuphistory 可以减小 msdb 数据库中历史记录表的大小。
----
Declare @dt datetime
Select @dt = cast(N'05/01/2010 00:00:00' as datetime)
   exec msdb.dbo.sp_delete_backuphistory @dt

----删除作业的历史记录
EXEC msdb.dbo.sp_purge_jobhistory  @oldest_date='05/01/2010 00:00:00'
EXEC msdb..sp_maintplan_delete_log null,null,'05/01/2010 00:00:00'


[参考资料2]

关于 SQL2005 远程备份

Rulition 10:19 2009-10-17

要实现 SQL 远程备份,必须处理好本机远程访问的问题:

第一、远程计算机与本机最好在同一网段内,如果跨了网段(或VLAN),需交换机路由支持,甚至修改本地路由表。

第二、为本机提供 SQL 服务的“用户名”和“密码”必须是[远程计算机]的[合法用户],且能对[远程计算机]的[备份文件夹]进行[完全操作]。
      一般情况下,在安装 SQL 服务时使用的是系统帐户(多半是 administrator),如果刚好是远程计算机的合法用户,则处理起来就简单多了。
      否则,在进行远程备份时必须使用 xp_cmdshell 调用 MS-DOS 的 net use 命令,使用对方的[合法用户]进行登记,以操作[备份文件夹]。
     
第三、至于[远程计算机]的[备份文件夹],可以事先在[远程计算机]上将[备份文件夹]进行共享,并指定可完全访问的用户名。
      如果不想让无关的人看到这个[备份文件夹],可在共享时将共享名后加上$,例如:备份文件夹$
      或者,在使用 net use 进行[合法用户]登记时,直接使用对方超级用户,这样可直接访问[备份文件夹]。
      例如:\\COMPUTER\E$\备份文件夹

      net use \\COMPUTER\E$\备份文件夹 /user:用户名 口令

      如果是空口令,可用""代替: /user:用户名 ""


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Rulition/archive/2009/10/17/4688982.aspx


*/


posted @ 2014-02-13 15:51  zhangchun  阅读(6031)  评论(0编辑  收藏  举报