MS SQL/Powershell:如何终止可用性组中辅助节点上的后台进程

MS SQL/Powershell: how to kill background process on secondary node in Availability Group

我的环境中配置了 MS-SQL Server 2014 和永远在线的高可用性组(在 2 个节点上)。

我正在编写一个 Powershell 脚本,它从可用性组(在主服务器上)中删除数据库,然后应该将数据库删除到辅助服务器上。

大部分时间都有效,但并非总是如此...

我使用以下命令删除辅助服务器上的数据库(此时数据库已经从主服务器上的可用性组中删除,并且在辅助服务器上处于 "recovering" 状态) : $SecondaryServerConnection.Databases[$x.Name.ToString()].Drop()

失败时,我收到错误消息:

System.Management.Automation.MethodInvocationException: Exception calling "Drop" with "0" argument(s): "Drop failed for Database 'Customer_2'. " ---> Microsoft.SqlServer.Management.Smo.FailedOperationException: Drop failed for Database 'Customer_2'. ---> Microsoft.SqlServer.Management.Common.ExecutionFailureException: An exception occurred while executing a Transact-SQL statement or batch. ---> System.Data.SqlClient.SqlException: Cannot drop database "Customer_2" because it is currently in use.

当我在脚本为 运行 时检查数据库服务器 (sp_who2) 时,我看到数据库 "Customer_2" 有一个状态为 [=61] 的进程=]、命令="DB STARTUP" 和 LastWaitType="REDO_THREAD_PENDING WORK".

一旦脚本失败,"Customer_2" 的进程就会消失。

我试图修改我的脚本以终止所有进程,但是当我这样做时,我收到错误消息:Only user processes can be killed.

如果它发生,它总是发生在第二个数据库上。可用性组中有几个数据库 (3 - 5)。

所以,现在我有几个问题:

我还没有找到为什么它适用于某些数据库而不适用于其他数据库的原因。这可能是数据库大小的问题。有些只有几百 MB,而另一些则高达 40Gb...

我无法将数据库设置为离线或将其设置为单用户模式,因为数据库在辅助服务器上不在线。数据库处于状态 "Restoring".

更新: 我忘记提及的是进程的 SPID 通常在 50 以上。根据我的阅读,低于 50 的 SPID 始终是系统进程。对吗?

您可以试试这个脚本,它会杀死指定数据库中的所有活动进程:

DECLARE @sql varchar(50); 
DECLARE @dbname sysname;
DECLARE @killStmts TABLE (stmt varchar(30));

SET @dbname = 'yourDatabase'; -- Set this to your database name

INSERT INTO @killStmts 
    SELECT 'KILL ' + CONVERT(varchar(10), [spid])
     FROM master..sysprocesses pr
          INNER JOIN master..sysdatabases db ON pr.[dbid] = db.[dbid]
    WHERE db.name = @dbname

DECLARE @killCtr int;

SELECT @killCtr = COUNT(1) FROM @killStmts;

WHILE (@killCtr > 0)
BEGIN
    SELECT TOP 1 @sql = stmt FROM @killStmts ORDER BY stmt;
    EXEC (@sql);
    DELETE @killStmts WHERE stmt = @sql;
    SELECT @killCtr = @killCtr - 1;
END

您可以将其改编成一个存储过程(将其安装到 master 数据库中,以便您可以为您喜欢的任何其他用户数据库调用它),它可以由 PowerShell 调用,或者您可以尝试将此脚本改编为 PowerShell本身。

我找到了这个问题的解决方案(但不是问题的根源)。

我最终编写了一个 Powershell 函数,该函数尝试使用 3 种不同的方法来删除数据库

Function Remove-SqlDatabase
{
[CmdletBinding()]
Param(
[string]$Server,
[string]$Database
)

try
{
    $smo = New-SMOconnection -server $Server
    $smo.KillDatabase($Database)
    $smo.Refresh()
    #Write-Host "Successfully dropped $Database on $($smo.name)"
}
catch
{
    try
    {
        $smo.Databases[$Database].Drop()
        #Write-Host "Successfully dropped $Database on $($smo.name)"
    }
    catch
    {
        try
        {
            $null = $smo.ConnectionContext.ExecuteNonQuery("DROP DATABASE $Database")
            #Write-Host "Successfully dropped $Database on $($smo.name)"
        }
        catch 
        { 
            Write-Error "Could not drop database $Database!"
            Write-Error $_
            throw $_
        }
    }
}
}