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

Microsoft.SqlServer.Management.Smo.Server.SqlRestore timeout issues

我有一个脚本,我根据找到的脚本创建了一个 powershell 脚本,Start-Migration。这是一个很棒的剧本,给了我很多非常好的想法;但是,在尝试恢复大型数据库或需要超过 10 分钟的数据库时,我 运行 遇到了一些问题。我试图同时使用我发现的 invoke-sqlcmd2 函数和 class 来恢复 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),在我的大型数据库上它 returns 说脚本超时。我想弄清楚如何纠正这个问题。我试过增加 statementtimeout = 1200 并且它在 10 分钟后仍然停止。我什至尝试向我们调用 invoke-sqlcmd 如您所见,我在尝试不同的选项时将其注释掉了。我现在束手无策。

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

我认为“$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 行的工作!

如何使用还原-SQL数据库代替

这样简单多了,我想你会非常感谢我的。

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

然后...就是这样。一条线!与以前不同,您还可以在此处轻松指定超时。指定最大超时:

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

这应该可以帮助您入门。相信我,使用 Cmdlet 比使用您在网上找到的一些随机脚本要容易得多。

好的,我让它工作了。我不完全确定它为什么起作用,但这就是我所做的。我创建了一个参数 $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

现在它保持打开状态的时间足以完成恢复过程。