3

我成功地使用 Powershell 和 SMO 来备份大多数数据库。但是,我有几个大型数据库,其中收到“超时”错误“System.Data.SqlClient.SqlException:超时已过期”。超时始终发生在 10 分钟。我尝试将 ConnectionContext.StatementTimeout 设置为 0、6000 和 [System.Int32]::MaxValue。设置没有任何区别。我发现许多 Google 参考资料表明将其设置为 0 使其不受限制。无论我尝试什么,超时始终发生在 10 分钟。我什至将服务器上的远程查询超时设置为 0(通过 Studio Manager),但无济于事。下面是我设置超时和实际备份功能的 SMO 连接。下面是我的脚本的输出。

更新 有趣的是,我使用 VS 2008 在 C# 中编写了备份功能,并且超时覆盖确实在该环境中工作。我正在将该 C# 进程合并到我的 Powershell 脚本中,直到我找出为什么超时覆盖不适用于 Powershell。这非常烦人!

function New-SMOconnection {
    Param ($server, 
        $ApplicationName= "PowerShell SMO", 
        [int]$StatementTimeout = 0
    )
#    Write-Debug "Function: New-SMOconnection $server $connectionname $commandtimeout"
    if (test-path variable:\conn) {
        $conn.connectioncontext.disconnect()
    } else {
        $conn = New-Object('Microsoft.SqlServer.Management.Smo.Server') $server
    }
    $conn.connectioncontext.applicationName = $applicationName
    $conn.ConnectionContext.StatementTimeout = $StatementTimeout
    $conn.connectioncontext.Connect()
    $conn
}

$smo = New-SMOConnection -server $server
if ($smo.connectioncontext.isopen -eq $false) {
    Throw "Could not connect to server $($server)."
}

Function Backup-Database {
Param([string]$dbname)
$db = $smo.Databases.get_Item($dbname)
if (!$db) {"Database $dbname was not found"; Return}
$sqldir = $smo.Settings.BackupDirectory +  "\$($smo.name -replace ("\\", "$"))"
$s = ($server.Split('\'))[0]
$basedir = "\\$s\" + $($sqldir -replace (":", "$"))

$dt = get-date -format yyyyMMdd-HHmmss        
$dbbk = new-object ('Microsoft.SqlServer.Management.Smo.Backup')        
$dbbk.Action = 'Database'        
$dbbk.BackupSetDescription = "Full backup of " + $dbname        
$dbbk.BackupSetName = $dbname + " Backup"        
$dbbk.Database = $dbname        
$dbbk.MediaDescription = "Disk"  
$target = "$basedir\$dbname\FULL"
if (-not(Test-Path $target)) { New-Item $target -ItemType directory | Out-Null}
$device = "$sqldir\$dbname\FULL\" + $($server -replace("\\", "$")) + "_" + $dbname + "_FULL_" + $dt + ".bak"
$dbbk.Devices.AddDevice($device, 'File')
$dbbk.Initialize = $True
$dbbk.Incremental = $false
$dbbk.LogTruncation = [Microsoft.SqlServer.Management.Smo.BackupTruncateLogType]::Truncate
If (!$copyonly) { 
    If ($kill) {$smo.KillAllProcesses($dbname)}
    $dbbk.SqlBackupAsync($server) 
}
$dbbk

}


Started SQL backups for server LCFSQLxxx\SQLxxx at 05/06/2010 15:33:16
Statement TimeOut value set to 0.

DatabaseName    : OperationsManagerDW
StartBackupTime : 5/6/2010 3:33:16 PM
EndBackupTime   : 5/6/2010 3:43:17 PM
StartCopyTime   : 1/1/0001 12:00:00 AM
EndCopyTime     : 1/1/0001 12:00:00 AM
CopiedFiles     : 
Status          : Failed
ErrorMessage    : System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
                  The backup or restore was aborted.
                  10 percent processed.
                  20 percent processed.
                  30 percent processed.
                  40 percent processed.
                  50 percent processed.
                  60 percent processed.
                  70 percent processed.
                     at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
                     at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
                     at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
                     at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
                     at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async)
                     at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
                     at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
                     at Microsoft.SqlServer.Management.Common.ServerConnection.ExecuteNonQuery(String sqlCommand, ExecutionTypes executionType)

Ended backups at 05/06/2010 15:43:23
4

2 回答 2

5

“反复拍我的头,说‘我在想什么?’”。

我创建了一个新连接并使用它连接到服务器。但是,实际的备份语句使用 $server (servername) 而不是 $smo 服务器对象与已建立的连接。因此,备份语句实际上建立了一个没有连接属性的全新连接来重置默认语句超时。

将备份语句更改为

$dbbk.SqlBackupAsync($smo)

解决问题。

于 2010-06-17T21:14:48.100 回答
0

如果您使用 SqlBackAsync,您如何知道备份何时完成?我和你的原始代码有同样的问题......但我的代码有一个功能,它取决于备份是否成功完成。因此,如果我调用 async,我需要一个操作来轮询并检查备份是否完成。

于 2012-06-19T09:58:08.627 回答