Microsoft.SqlServer.Management.Smo.Server.SqlRestore超时问题

时间:2015-03-24 15:33:51

标签: database powershell restore

我有一个脚本,我根据我找到的脚本Start-Migration创建了一个PowerShell脚本。这是一个很棒的剧本,给了我很多很好的想法;但是,在尝试恢复超过10分钟的大型数据库或数据库时,我遇到了一些问题。我试图使用它们发现的invoke-sqlcmd2函数和microsoft.sqlserver.management.smo命名空间的恢复类。这两个都在10分钟后超时。我还尝试增加连接超时,甚至将连接设置为1200.任何建议都会受到欢迎。

Function Restore-SQLDatabase {
    <#
        .SYNOPSIS
            Restores .bak file to SQL database. Creates db if it doesn't exist. $filestructure is
            a custom object that contains logical and physical file locations.

        .EXAMPLE
            $filestructure = Get-SQLFileStructures $sourceserver $destserver $ReuseFolderstructure
            Restore-SQLDatabase $destserver $dbname $backupfile $filestructure   

        .OUTPUTS
            $true if success
            $true if failure
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [object]$server,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$dbname,


        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$backupfile,

        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [object]$filestructure

    )

$servername = $server.Name
$server.ConnectionContext.StatementTimeout = 0
$restore = New-Object "Microsoft.SqlServer.Management.Smo.Restore"

foreach ($file in $filestructure.databases[$dbname].destination.values) {
    $movefile = New-Object "Microsoft.SqlServer.Management.Smo.RelocateFile" 
    $movefile.LogicalFileName = $file.logical
    $movefile.PhysicalFileName = $file.physical
    $null = $restore.RelocateFiles.Add($movefile)
}

Write-Host "Restoring $dbname to $servername" -ForegroundColor Yellow

try{
      $Percent = [Microsoft.SqlServer.Management.Smo.PercentCompleteEventHandler]{
      Write-Progress -Id 1 -Activity "Restoring $dbname to $ServerName" -PercentComplete $_.Percent -Status ([System.String]::Format("Progress: {0}%",$_.Percent))
    }
    $restore.add_PercentComplete($Percent)
    $restore.PercentCompleteNotification = 1
    $restore.add_Complete($Complete)
    $restore.ReplaceDatabase = $true
    $restore.Database = $dbname
    $restore.Action = "Database"
    $restore.NoRecovery = $false
    $device = New-Object -TypeName Microsoft.SqlServer.Management.Smo.BackupDeviceItem
    $device.Name = $backupfile
    $device.DeviceType = "File"
    $restore.Devices.Add($device)


    Write-Progress -Id 1 -Activity "Restoring $dbname to $servername" -PercentComplete 0 -Status([System.String]::Format("Progress: {0}%",0))

    $restore.SqlRestore($servername)

    # $query = $restore.Script($ServerName)

    # Write-Host $query

    # Invoke-Sqlcmd2 -ServerInstance $servername -Database master -Query $query -ConnectionTimeout 1200

    # Write-Host "Restoring $dbname to $servername from " $restore.Devices.ToString() -ForegroundColor Magenta

    Write-Progress -Id 1 -Activity "Restore $dbname to $servername" -Status "Complete" -Completed

    return $true 
}
catch{

    Write-Error $_.Exception.ToString()

    Write-Warning "Restore failed: $($_.Exception.InnerException.Message)"

    return $false
}

当还原过程发生时,$ restore.SqlRestore($ ServerName),在我的大型数据库上,它返回说该脚本超时。我想弄清楚如何纠正这个问题。我已经尝试增加statementtimeout = 1200并且它在10分钟后仍然停止。我甚至试图给我们一个invoke-sqlcmd你可以看到我在尝试不同的选项时评论它。我现在正处于斗智斗勇的境地。

2 个答案:

答案 0 :(得分:0)

如果您必须使用找到的脚本

我认为这行`$ server.ConnectionContext.StatementTimeout = 0'实际上并没有做任何事情或更改超时阈值。

尝试将行更改为此行,而不是

$server = New-Object("Microsoft.SqlServer.Management.Smo.Server") $server
$server.ConnectionContext.StatementTimeout = 0
$server.ConnectionContext.Connect()

但是,我建议完全避免使用这种方法,因为您可以使用更简单的SQLPS Cmdlet。您使用的方法来自很久以前,我们没有实际的PowerShell cmdlet来使用SQL。

现在,我们有了Restore-SQLDatabase cmdlet,它允许你在一行中完成你的代码现在在~30行中所做的!!

如何使用Restore-SQLDatabase

这更容易,我想你真的会感谢我。

Restore-SqlDatabase -ServerInstance "$server\InstanceName" `
 -Database $dbname `-BackupFile $BackupFile

并且......就是这样。一条线!而且你也可以在这里轻松指定超时,这与之前不同。要指定最大超时:

Restore-SqlDatabase -ServerInstance "$server\InstanceName" `
 -Database $dbname -BackupFile $BackupFile -ConnectionTimeout 0

这应该让你开始。相信我,使用Cmdlet比使用在线查找的随机脚本要容易得多。

答案 1 :(得分:0)

好的,我让它上班了。我不完全确定它为什么有效,但这就是我所做的。我创建了一个参数$ Server,如下所示:

$Server = New-Object Microsoft.SqlServer.Management.Smo.Server $Source $Server.ConnectionContext.ConnectTimeout = 0

现在当我调用实际执行恢复的功能时,我正在做一些我不需要做的事情:

$ServerName = $server.Name

而不是使用$ ServerName,我使用对象$ server:

$restore.SqlRestore($servername) # Original Script
$restore.SqlRestore($server) # Change

现在它保持打开足够长的时间来完成恢复过程。