2010-05-06 65 views
3

我成功使用Powershell和SMO来备份大多数数据库。但是,我有几个大型数据库中收到“超时”错误“System.Data.SqlClient.SqlException:超时过期”。时光在10分钟时一直发生。我已经尝试将ConnectionContext.StatementTimeout设置为0,6000,并且设置为[System.Int32] :: MaxValue。设置没有区别。我发现许多Google参考文献指出将其设置为0使其无限。无论我尝试什么,超时都会持续10分钟。我甚至将服务器上的远程查询超时设置为0(通过Studio Manager)无济于事。以下是我设置超时和实际备份功能的SMO连接。下面是我的脚本的输出。忽略SMO ConnectionContext.StatementTimeout设置

UPDATE 有趣的是,我用C#编写了使用VS 2008的备份功能,超时重写在该环境下工作。我正在将该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 

回答

5

“屡拍我的头,说: '我在想什么?'”。

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

更改备份语句

$dbbk.SqlBackupAsync($smo) 

解决了这个问题。

+1

我正在使用SqlBackup而不是SqlBakcupAsync,但此技巧仍适用于我。我正在传递服务器名称,以便创建新的连接。在切换到将ConnectionContext.StatementTimeout设置为[Int32] :: MaxValue的服务器对象后,我可以在没有命令超时的情况下执行备份。 – 2012-12-20 21:17:59

0

如果您使用SqlBackAsync,您会如何知道备份何时完成? 我和你的原代码有同样的问题......但是我的代码有一个依赖备份的功能,已经成功完成。 所以如果我打电话异步我需要一个操作轮询和检查备份完成。