今天研究阿里雲服務數據庫的遷移,備份和還原的時候,在阿里雲web后台發現了一個很好用的sql腳本,就默默地偷了過來,它可以支持全量備份,差異備份和日志備份,代碼解釋也都很清楚,我也嘗試着跑了一下,性能也還是蠻不錯的,本地電腦運行壓縮后1個多G的數據備份用了二十多秒
我們可以將下面代碼放到SQL作業里面,然后定期的去做全量和差異的備份,這不免也算是一種不錯的數據庫備份方案了,當然這種備份功能完全可以用SqlServer自帶的數據庫維護計划功能代替,而且阿里雲等類似的雲數據庫都是會提供數據備份服務的,不需要開發人員自己做數據備份。
代碼如下,如果有用阿里雲服務器的碼友可以直接到用戶后台下載最新源碼
USE master GO /** * author: * jianming.wjm@alibaba-inc.com of Alibaba Cloud Team. * * @purpose: * Backup your databases to local directory (no matter destination folder exist or not). * You can personal your backup type, support three backup types include(FULL, DIFF, LOG). * This script also support just check to see details or run directly. * * if you find something happen unhappy, please kindly tell us via the author email. thanks. * * @usage: * Copy all the script (ctrl + a) into SSMS, fill out the public variables and then F5 or Execute it. * * @parameters: * @backup_databases_list: databases list needed to backup * @backup_type: which backup type needed, choice one of ['FULL', 'DIFF', 'LOG'] * @backup_folder: where backup files located * @is_run: I want to run or just check, 1: run; 0: just check. * * @version: * 1.0.0, 2018/03/02 15:20: Create script. * * @Tips: * We'd like to advice you to change your databases to FULL recovery model to improve migrate to RDS. * example: ALTER DATABASE [db_simple] SET RECOVERY FULL WITH NO_WAIT * pay attention to the SSMS output messages, and correct the error if have any. **/ SET NOCOUNT ON -- declare public variables DECLARE @backup_databases_list NVARCHAR(max), @backup_type SYSNAME, @backup_folder SYSNAME, @is_run TINYINT ; -- YOU HAVE TO INIT PUBLIC VARIABLES HERE!!!! SELECT /** * Databases list needed to backup, delimiter is ; or , * empty('') or null: means all databases excluding system database * example: '[testdb];TestDR,Test,readonly' **/ @backup_databases_list = N'[TestA];[TestB],readonly,Test', @backup_type = N'FULL', -- Backup Type? FULL: FULL backup; DIFF: Differential backup; LOG: Log backup @backup_folder = N'C:\BACKUP', -- Backup folder to store backup files. @is_run = 1 -- Check or run? 1, run directly; 0, just check ; -- variables checking IF @backup_type NOT IN(N'FULL', N'DIFF', N'LOG') BEGIN RAISERROR('Backup type %s is not supported!', 16, 1, @backup_type) RETURN END ; IF ISNULL(@backup_folder, N'') = N'' BEGIN RAISERROR('backup_folder is not allow empty!', 16, 1) RETURN END IF @is_run NOT IN(0, 1) BEGIN RAISERROR('is_run parameter should be 0 or 1 !', 16, 1) RETURN END -- declare private variables DECLARE @database_name SYSNAME, @database_state TINYINT, @database_state_desc NVARCHAR(60), @database_count INT, @database_do INT, @flag_edition BIT, @exec_sql NVARCHAR(MAX), @timestamp VARCHAR(20), @context_info VARCHAR(20), @backup_databases_list_XML XML ; -- private variables init. SELECT @database_name = N'', @database_state = 11, @database_state_desc = N'', @database_count = 0, @database_do = 1, @flag_edition = CASE WHEN CONVERT(sysname, SERVERPROPERTY(N'Edition')) LIKE N'Enterprise%' THEN 1 ELSE 0 END, @exec_sql = N'', @timestamp = REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(19), GETDATE(),120), N'-', N''), N':', N''), CHAR(32), N''), @backup_folder = CASE WHEN RIGHT(@backup_folder, 1) = N'\' THEN @backup_folder ELSE @backup_folder + N'\' END, @context_info = N'0x1256698449', @backup_databases_list_XML = N'<V><![CDATA[' + REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( @backup_databases_list, '[', '' ), ']', '' ), ';', ',' ),CHAR(10),']]></V><V><![CDATA[' ),',',']]></V><V><![CDATA[' ),CHAR(13),']]></V><V><![CDATA[' ) + ']]></V>' ; -- temp table declare to save databases splitted IF OBJECT_ID('tempdb..#tmp_databases', 'U') IS NOT NULL DROP TABLE #tmp_databases CREATE TABLE #tmp_databases( RowId INT IDENTITY(1,1) NOT NULL PRIMARY KEY, Database_name SYSNAME ) ; -- get databases name IF ISNULL(@backup_databases_list, N'') > N'' BEGIN INSERT INTO #tmp_databases SELECT DISTINCT [Database_name] = T.C.value('(./text())[1]','sysname') FROM @backup_databases_list_XML.nodes('./V') AS T(C) WHERE T.C.value('(./text())[1]','sysname') IS NOT NULL ; END ELSE BEGIN INSERT INTO #tmp_databases SELECT DISTINCT name FROM sys.databases WITH (NOLOCK) WHERE name NOT IN (N'master', N'tempdb', N'model', N'msdb', N'distribution') END -- decalre cursor to loop each database. DECLARE CUR_DatabaseList CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY FOR SELECT DISTINCT name, state, state_desc FROM sys.databases WITH (NOLOCK) WHERE name IN(SELECT [Database_name] FROM #tmp_databases) -- Open cursor and get the rowcount OPEN CUR_DatabaseList FETCH NEXT FROM CUR_DatabaseList INTO @database_name, @database_state, @database_state_desc SET @database_count = @@CURSOR_ROWS; -- prepare folder on local host. IF @database_count > 0 BEGIN EXEC sys.xp_create_subdir @backup_folder END WHILE @@FETCH_STATUS = 0 BEGIN -- contact the backup script for each backup type. SET @exec_sql = CASE WHEN @backup_type = N'FULL' THEN N'BACKUP DATABASE ' + QUOTENAME(@database_name) + N' TO DISK = N' + QUOTENAME(@backup_folder + @database_name + N'_' + @backup_type + N'_' + @timestamp + N'.bak', '''') + N' WITH STATS = 1' + CASE WHEN @flag_edition = 1 THEN N', COMPRESSION;' ELSE N';' END WHEN @backup_type = N'DIFF' THEN N'BACKUP DATABASE ' + QUOTENAME(@database_name) + N' TO DISK = N' + QUOTENAME(@backup_folder + @database_name + N'_' + @backup_type + N'_' + @timestamp + N'.bak', '''') + N' WITH DIFFERENTIAL, STATS = 1' + CASE WHEN @flag_edition = 1 THEN N', COMPRESSION;' ELSE N';' END WHEN @backup_type = N'LOG' THEN N'BACKUP LOG ' + QUOTENAME(@database_name) + N' TO DISK = N' + QUOTENAME(@backup_folder + @database_name + N'_' + @backup_type + N'_' + @timestamp + N'.bak', '''') + N' WITH STATS = 1' + CASE WHEN @flag_edition = 1 THEN N', COMPRESSION;' ELSE N';' END ELSE N'' END ; RAISERROR('--==============%d/%d: Working on database: %s', 10, 1, @database_do , @database_count, @database_name) WITH NOWAIT; --Only online database can be Backup. IF @database_state = 0 BEGIN RAISERROR('-- %s', 10, 1, @exec_sql) WITH NOWAIT; IF @is_run = 1 BEGIN SET @exec_sql = N'SET CONTEXT_INFO ' + @context_info + N';' + @exec_sql ; EXEC sys.sp_executesql @exec_sql END END ELSE BEGIN RAISERROR('-- database %s state: %s can''t be backup, skipped.', 10, 1, @database_name, @database_state_desc) WITH NOWAIT; END SET @database_do = @database_do + 1; FETCH NEXT FROM CUR_DatabaseList INTO @database_name, @database_state, @database_state_desc END -- close and release cursor. CLOSE CUR_DatabaseList DEALLOCATE CUR_DatabaseList GO
還有一點需要注意的是阿里雲雲數據庫RDS是不支持數據庫直接操作還原的,在雲數據庫上操作還原數據庫會報如下錯誤
那么我們如何在阿里雲數據庫還原數據呢?人家阿里雲爸爸也提供了相應的解決方案——OSS備份數據恢復,它可以將指定數據庫文件還原到雲數據庫
相關功能可以參考鏈接 https://help.aliyun.com/document_detail/68310.html