使用PowerShell 命令集進行SQL Server 2012 備份和還原


最近心相不錯,所以打算翻譯一些英文文檔做福利,原文在此,翻譯有不足的地方還請各位兄弟指點.

討論什么是DBA最重要的工作的時候,你最常聽到就是一條就是DBA只要做好備份和恢復.事實如此,如果你不做備份,或者無法保證你的備份能夠有效恢復,你和你的公司就會處於數據丟失危險下.

T-SQL 命令BACKUP DATABASE已經使用了相當長的一段時間(在這之前用的是DUMP DATABASE 命令,老人們都記得). 它仍然不失為備份數據庫好方式.我們現在有一個新的方法來自動的做這些日常的備份處理任務.在本文中我會通過實例來介紹如何通過PowerShell腳本來備份.並告訴大家在SQL Server 2012 使用PowerShell Cmdlet的便利性.

在SQL Server 2012 中,微軟增加了4個新的備份和還原的cmdlet

  • Backup-SqlDatabase
  • Restore-SqlDatabase
  • Backup-ASDatabase
  • Restore-ASDatabase

為什么要通過外部程序來做腳本備份?

當備份工作越來越復雜,越來越多文件系統要被牽涉進去的時候.這些工作可能需要建立並按放備份文件至某個目錄,刪掉不需要的舊備份,異地拷貝,檢查備份完整性,寫入日志等等. 你也可能想一步操作就把在不同服務器上的多個數據庫進行備份或者拷貝數據庫到幾個服務器或者虛擬機上做測試.這個時候備份和還原就需要考慮使用腳本,而PowerShell擅長此道.

 

使用Powershell和SMO編寫腳本

在2009年我發布了白皮書backup.ps1 ,使用SMO(Server Management Objects)庫來備份你的數據庫.SMO支持SQL Server versions 2000 ~ 2012, 微軟在SQL Server 2012並沒有給SMO增加多少新的特性.所以沒多少新東西可學.

在白皮書中我講述了SQL Server snapins , 還有SQL Server 2008 和 SQL Server 2008 R2 里面的迷你Shell (SQLPS.exe) ,PowerShell 團隊為 SQL Server 2008 擴展的,現在技術已經改變 , 采用”模塊”來擴展Powershell   因此, SQL Server 2012 安裝的時候Powershell 最低版本是2.0 , 然后 SQLPS.exe 程序已經被替換掉了(叫SQLPS = =).

微軟在SQLPS模塊中提供了一些新的cmdlets, 多數專門用來管理可用性組和高可用性還有災難恢復. 他們新增了備份和還原操作的 cmdlets , Backup-SqlDatabase, Restore-SqlDatabase, Backup-ASDatabase 還有 Restore-ASDatabase.

 

安裝SQLPS模塊

啟動 PowerShell 並且想要使用SQLPS模塊, 你需要導入相應的cmdlet. 開啟PowerShell 2.0,當導入模塊的時候微軟會通過一個列表來進行動詞的檢查.Backup 和 Restore並不在這個列表里面,所以你執行模塊導入的時候會報錯. 你可以使用 -DisableNameChecking 參數來避免這個錯誤

(譯者注:我執行的時候報錯. 提示SQLPS不被信任,所以模塊導入出錯了, 此時要執行Set-ExecutionPolicy RemoteSigned 來開啟)

SNAGHTML3896cce8

使用Backup-SqlDatabase CmdLet來備份數據庫

簡單的 Backup-SQLDatabase 語句

當你導入模塊以后,可以先簡單的建立個備份數據庫的腳本,如下:

{$dt = Get-Date -Format yyyyMMddHHmmss
$dbname = 'AdventureWorks'
Backup-SqlDatabase -ServerInstance TESTSQL -Database $dbname -BackupFile "E:\Backup\$($dbname)_db_$($dt).bak"

有很多的方法來調用這個指令,比如說你可以使用Get-ChildItem來獲取你定位到的數據庫實例的目錄數據庫名,然后通過管道發送給Backup-SqlDatabase命令,進行迭代的進行數據庫備份 . 因為你已經連到你的實例這里所以就不需要在加 -ServerInstance 參數了.

簡單打下面兩句就了…

Set-Location SQLSERVER:\SQL\
TESTSQL
\DEFAULT\Databases
get-childitem|Backup-SqlDatabase

備份會放在默認的備份目錄里面, 備份文件名也是默認的數據庫名字. 如果你想指定備份文件的名字,或者其他一些闡述,可以用下面的代碼 

Set-Location SQLSERVER:\SQL\TESTSQL\DEFAULT\Databases
foreach ($db in (Get-ChildItem))
    {
        $dbname = $db.Name
        $dt = Get-Date -Format yyyyMMddHHmmss
        Backup-SqlDatabase -Database $dbname -BackupFile "$($dbname)_db_$($dt).bak" 
    }

下面段會備份所有用戶數據庫被分到默認備份目錄,並且以數據庫的名字和當前日期時間作為備份文件的名字. (如果你使用 Get-ChildItem 加上-Force 參數,那就會包含系統數據庫,當然 tempdb被Where過濾掉了.)

get-childitem -force|where name -ne 'TempDB'| Backup-SqlDatabase

你也可以建立一個包含 SMO Server 對象的腳本 , 用 -InputObject 代替-ServerInstance . 雖然我們示例是備份一個數據庫,但是這個在處理多服務器上的數據庫的時候會很有用.

$dt = Get-Date -Format yyyyMMddHHmmss
$dbname = 'AdventureWorks'
$svr =  new-object ('Microsoft.SqlServer.Management.Smo.Server') 'TESTSQL'
Backup-SqlDatabase -InputObject $svr -Database $dbname -BackupFile "E:\Backup\$($dbname)_db_$($dt).bak"

另外你也可以使用一個包含SMO數據庫的變量,然后使用 -DatabaseObject 參數.

$dt = Get-Date -Format yyyyMMddHHmmss
Set-Location SQLSERVER:\SQL\TESTSQL\DEFAULT\Databases\AdventureWorks
$db = Get-Item .
$dbname = $db.Name
Backup-SqlDatabase -DatabaseObject $db -BackupFile "E:\Backup\$($dbname)_db_$($dt).bak"

以上示例為了便於理解,均使用了最少的參數,實際操作的話,你應該看一下其他參數,使得備份方案符合你的需求. 

SQL備份: 關鍵參數

我通常會加參數 -BackupAction. 選項可以是Database,Files和Log,默認是Database, 如果你想做差異備份,那么指定 BackupAction  為Database ,然后加上-Incremental參數.如果你想備份單個文件或者文件組,你可以使用 Files 選項.而 Log 選項允許你做事務日志備份.為了節省篇幅,因此去掉了這些參數. 所以例子直接備份了整個數據庫.

舉個例子,我總是會使用-CompressionOption 參數. 當然還有-ConnectionTimeout ,並且設置為0  ,因為你不想備份的時候因為超時而被中斷.

我們用get-help 獲得 Backup-SqlDatabase 的參數列表 :

Backup-SqlDatabase

[-Database] <string>

[-BackupFile] <string[]>]

[-ServerInstance <string[]> ]

[-BackupAction <BackupActionType>]

[-BackupDevice <BackupDeviceItem[]>]

[-BackupSetDescription <string>]

[-BackupSetName <string>]

[-BlockSize <int>]

[-BufferCount <int>]

[-Checksum]

[-CompressionOption <BackupCompressionOptions>]

[-ConnectionTimeout <int>]

[-ContinueAfterError]

[-CopyOnly]

[-Credential <PSCredential>]

[-DatabaseFile <string[]>]

[-DatabaseFileGroup <string[]>]

[-ExpirationDate <DateTime>]

[-FormatMedia]

[-Incremental]

[-Initialize]

[-LogTruncationType <BackupTruncateLogType>]

[-MaxTransferSize <int>]

[-MediaDescription <string>]

[-MediaName <string>]

[-MirrorDevices <BackupDeviceList[]>]

[-NoRecovery]

[-NoRewind]

[-Passthru]

[-Restart]

[-RetainDays <int>]

[-Script]

[-SkipTapeHeader]

[-UndoFileName <string>]

[-UnloadTapeAfter]

[-Confirm]

[-WhatIf]

[<CommonParameters>]

 

比SMO顯著的優勢

最明顯的就是在命令集中增加了一些SMO沒有的功能.比如通過Transact-SQL可以設置備份的塊大小和緩沖區數而SMO沒有.下圖是等價功能的SMO的備份對象的屬性和方法:

(上圖是通過Visual Studio 的 Object Browser 載入SMOExtended DLL的截圖)

 

使用Restore-SQLDatabase CmdLet 還原數據庫

總歸有各種各樣的原因需要還原數據庫, 所以…還原的選項比備份的還要多.

下面是恢復full backup一個簡單示例, 選項設置直接覆蓋現有數據庫.

Restore-SqlDatabase -ServerInstance TESTSQL -Database AdventureWorks `
-BackupFile "E:\Backup\AdventureWorks_db_20130420153024.bak" -ReplaceDatabase

我還原數據庫最頻繁的理由之一就是用戶不小心刪掉了數據,隨后又被事務更新,導致數據丟失.碰到這種情況我就要用另外一個名字還原該數據庫,然后把需要的數據復制過去.

 

通過 SMO 還原數據庫

下面是我們使用SMO還原的代碼

# Connect to the specified instance
$srv = new-object ('Microsoft.SqlServer.Management.Smo.Server') 'TESTSQL'
 

# Get the default file and log locations
# (If DefaultFile and DefaultLog are empty, use the MasterDBPath and MasterDBLogPath values)
$fileloc = $srv.Settings.DefaultFile
$logloc = $srv.Settings.DefaultLog
if ($fileloc.Length -eq 0) {
    $fileloc = $srv.Information.MasterDBPath
    }
if ($logloc.Length -eq 0) {
    $logloc = $srv.Information.MasterDBLogPath
    }
 

# Identify the backup file to use, and the name of the database copy to create
$bckfile = 'E:\Backup\AdventureWorks_db_20101016135438.bak'
$dbname = 'AdventureWorks_20101016'
 

# Build the physical file names for the database copy
$dbfile = $fileloc + '\'+ $dbname + '_Data.mdf'
$logfile = $logloc + '\'+ $dbname + '_Log.ldf'
 

# Use the backup file name to create the backup device
$bdi = new-object ('Microsoft.SqlServer.Management.Smo.BackupDeviceItem') ($bckfile, 'File')
 

# Create the new restore object, set the database name and add the backup device
$rs = new-object('Microsoft.SqlServer.Management.Smo.Restore')
$rs.Database = $dbname
$rs.Devices.Add($bdi)
 

# Get the file list info from the backup file
$fl = $rs.ReadFileList($srv)
foreach ($fil in $fl) {
    $rsfile = new-object('Microsoft.SqlServer.Management.Smo.RelocateFile')
    $rsfile.LogicalFileName = $fil.LogicalName
    if ($fil.Type -eq 'D'){
        $rsfile.PhysicalFileName = $dbfile
        }
    else {
        $rsfile.PhysicalFileName = $logfile
        }
    $rs.RelocateFiles.Add($rsfile)
    }
 

# Restore the database
$rs.SqlRestore($srv)

還原一個已存在的數據庫的問題就是物理名稱沖突,要解決這個問題SMO 可以使用RelocateFile 對象. 這和Transact-SQL 使用 WITH MOVE 條件一樣. 有趣的是Restore-SqlDatabase 命令也使用SMO 對象處理這個事情.

使用純SMO 和 Restore-SqlDatabase 命令的唯一區就是何存儲和傳遞RelocateFile 對象. 建立一個空的集合,然后讀取備份文件列表,並且把每個RelocateFile 的每個對象都添加到集合中.  隨后調用 Restore-SqlDatabase命令. 下圖中最后最后一部分用的是新的cmdlet,其他上面的例子都一樣.

# Get the file list info from the backup file
$fl = $rs.ReadFileList($srv)
$rfl = @()
foreach ($fil in $fl) {
    $rsfile = new-object('Microsoft.SqlServer.Management.Smo.RelocateFile')
    $rsfile.LogicalFileName = $fil.LogicalName
    if ($fil.Type -eq 'D') {
        $rsfile.PhysicalFileName = $dbfile
        }
    else {
        $rsfile.PhysicalFileName = $logfile
        }
    $rfl += $rsfile
    }
 

# Restore the database
Restore-SqlDatabase -ServerInstance TESTSQL -Database $dbname `
 -BackupFile "E:\Backup\AdventureWorks_db_20101016135438.bak" `
 -RelocateFile $rfl

在本例中我貼出了純SMO的例子,應該已經很清楚了.

 

指定一個時間點來還原數據庫

最后一個例子是通過一個時間點來還原數據庫. 有時候你知道問題發生的時間,你可以恢復到那個時間點.

在這個情境中我們所有的被封文件都放在本地服務器的 E:\Backup 目錄. 我們有很多完全備份,差異備份,還有一些事務日志備份文件用來做某一個時間點的還原.文件名格式為 DatabaseName_type_datetime.ext, 其中type是db, diff 和 tran ,ext是 bak 或 trn.

$dbname = 'AdventureWorks'
$restorept = '2013-04-20 15:30:00'
Set-Location 'E:\Backup'
$fullfile = Get-ChildItem -Filter "$($dbname)_db_*" | Where-Object {$_.LastWriteTime -lt $restorept} | Sort-Object LastWriteTime Desc | Select-Object -First 1
$difffile = Get-ChildItem -Filter "$($dbname)_diff_*" | Where-Object {$_.LastWriteTime -lt $restorept} | Sort-Object LastWriteTime Desc | Select-Object -First 1
$tranfile = Get-ChildItem -Filter "$($dbname)_tran_*" | Where-Object {$_.LastWriteTime -gt $difffile.LastWriteTime} | Sort-Object LastWriteTime Asc

$fullfile 變量包含指定時間點前的完整備份文件信息,$difffile變量包含指定時間點前的差異備份文件信息 , $tranfile 包含差異備份后至指定時間點前的所有的事務日志文件信息

首先我們需要還原完整備份, 並且指定 no recovery選項.

Restore-SqlDatabase -ServerInstance TESTSQL -Database $dbname `
-BackupFile $fullfile.FullName -ReplaceDatabase `
-NoRecovery

然后我們還原最后一個差異備份,同樣的,指定no recovery選項.

Restore-SqlDatabase -ServerInstance TESTSQL -Database $dbname `
-BackupFile $difffile.FullName -ReplaceDatabase `
-NoRecovery

最后我們通過循環來讀取$tranfile變量中的文件來還原事務日志, 如果LastWriteTime 屬性比 $restorept 變量小,那么恢復的時候指定no recovery,然后處理下一個,否則,則根據-ToPointInTime 參數指定的時間點來還原. 不加-NoRecovery 參數,至此整個還原過程結束.

$recovery = 0
foreach ($trnfile in $tranfile) {
     if ($trnfile.LastWriteTime -lt $restorept) {
         Restore-SqlDatabase -ServerInstance TESTSQL -Database $dbname `
-BackupFile $trnfile.FullName -ReplaceDatabase `
-NoRecovery
         }
    else {
         if ($recovery -eq 0) {
             Restore-SqlDatabase -ServerInstance TESTSQL -Database $dbname `
-BackupFile $trnfile.FullName -ReplaceDatabase `
-ToPointInTime $restorept
$recovery = 1        
            }
        }
    }

還有很多特性,結合通過操作系統的一些功能來做備份和還原操作,比用Transact-SQL要方便許多

下圖是SMO Restore 對象的屬性和方法:

相應的下面是Restore-SqlDatabase的參數

Restore-SqlDatabase

[-Database] <string>

[[-BackupFile] <string[]>]

-ServerInstance <string[]>

[-BackupDevice <BackupDeviceItem[]>]

[-BlockSize <int>]

[-BufferCount <int>]

[-Checksum]

[-ClearSuspectPageTable]

[-ConnectionTimeout <int>]

[-ContinueAfterError]

[-Credential <PSCredential>]

[-DatabaseFile <string[]>]

[-DatabaseFileGroup <string[]>]

[-FileNumber <int>]

[-KeepReplication]

[-MaxTransferSize <int>]

[-MediaName <string>]

[-NoRecovery]

[-NoRewind]

[-Offset <Int64[]>]

[-Partial]

[-Passthru]

[-RelocateFile <RelocateFile[]>]

[-ReplaceDatabase]

[-Restart]

[-RestoreAction <RestoreActionType>]

[-RestrictedUser]

[-Script]

[-StandbyFile <string>]

[-StopAtMarkAfterDate <string>]

[-StopAtMarkName <string>]

[-StopBeforeMarkAfterDate <string>]

[-StopBeforeMarkName <string>]

[-ToPointInTime <string>]

[-UnloadTapeAfter]

[-Confirm]

[-WhatIf]

[<CommonParameters>]

 

使用Backup-ASDatabase備份 Analysis Services

Analysis Services 的數據庫也是需要備份的,雖然沒多少選項可用. 首先你需要載入Analysis Services  命令集的模塊 .

Import-Module SQLASCMDLETS

我們先看下 Backup-ASDatabase的所有參數.

Backup-ASDatabase

[-BackupFile] <string>

[-Name] <string>

[-AllowOverwrite <SwitchParameter>]

[-BackupRemotePartitions <SwitchParameter>]

[-ApplyCompression <SwitchParameter>]

[-FilePassword <SecureString>]

[-Locations <Microsoft.AnalysisServices.BackupLocation[]>]

[-Server <string>]

[-Credentials <PSCredential>]

[<CommonParameters>]

注意:這里沒有差異備份或者日志備份的選項.下面是備份AWDB database一個簡單例子.

Backup-ASDatabase "E:\Backup\AWDB.abf" AWDB

如果需要覆蓋已存在的數據庫備份,可以加上 -AllowOverwrite 參數,需要壓縮備份則加上-ApplyCompression參數, 要加密的話可以使用 -FilePassword 參數.

 

使用Restore-ASDatabase還原 Analysis Services數據庫

同樣的還原Analysis Services 數據庫也沒多少可用選項.

Restore-ASDatabase

[-RestoreFile] <string>

[-Name] <System.String>

[-AllowOverwrite <SwitchParameter>]

[-Locations <Microsoft.AnalysisServices.RestoreLocation[]>]

[-Security <Microsoft.AnalysisServices.RestoreSecurity>]

[-Password <System.SecureString>]

[-StorageLocation <System.String>]

[-Server <string>]

[-Credentials <PSCredential>] [<CommonParameters>]

下面是一個還原例子

Restore-ASDatabase "E:\Backup\AWDB.abf" AWDB -Security:CopyAll

還原的時候同事恢復roles和members

 

總結

組織數據的備份還原是至關重要的.使用Powershell和SMO編寫腳本來管理SQL SERVER的備份還原是最好的,尤其是DBA需要完成更復雜,的重復性的任務的時候. 比如數據庫需要高可用性, 我們可以創建腳本來重建他們,進行高可用性測試排練.總之 在 SQL Server 2012中使用他們最理想的,而且很方便.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM