我有一个配置了MS-SQL Server 2014和始终在线高可用性组的环境(在2个节点上)。
我正在编写一个Powershell脚本,它从可用性组中删除数据库(在主服务器上),然后应该将数据库放在辅助服务器上。
大部分时间都有效,但并非总是......
我使用以下命令将数据库删除到辅助服务器上(此时数据库已从主服务器上的可用性组中删除,并且在辅助服务器上处于“正在恢复”状态):
$SecondaryServerConnection.Databases[$x.Name.ToString()].Drop()
当它失败时,我收到错误消息:
System.Management.Automation.MethodInvocationException:使用“0”参数调用“Drop”的异常:“数据库丢弃失败 'Customer_2'。 “ ---> Microsoft.SqlServer.Management.Smo.FailedOperationException:数据库'Customer_2'的丢弃失败。 ---> Microsoft.SqlServer.Management.Common.ExecutionFailureException:执行Transact-SQL语句时发生异常或 批量。 ---> System.Data.SqlClient.SqlException:无法删除数据库“Customer_2”,因为它当前正在使用中。
当我在脚本运行时检查DB-Server(sp_who2)时,我看到DB“Customer_2”的进程有Status =“background”,Command =“DB STARTUP”和LastWaitType =“REDO_THREAD_PENDING WORK”。
一旦脚本失败,“Customer_2”的过程就会消失。
我尝试修改我的脚本以终止所有进程,但是当我这样做时,我收到错误消息:Only user processes can be killed.
如果发生,它总是在第二个数据库上发生。在可用性组中有几个数据库(3 - 5)。
所以,现在我有几个问题:
如何在Powershell脚本中摆脱后台进程?是否可以这样做?
为什么它适用于第一个数据库而不是第二个数据库?我的脚本是否在该数据库上有进程,因此该进程仅在脚本失败后消失?
或者在主服务器上删除了数据库后,这是一个时间问题吗?放弃后我有6秒start-sleep
..
无论如何,这些过程是什么?它们存在于辅助服务器上的所有数据库中。
我没有找到它在某些数据库上运行的原因而在其他一些数据库上没有...它可能是数据库大小的问题..有些只是几百MB,而其他人则是40GB ...
我无法将数据库设置为脱机或将其设置为单用户模式,因为数据库在辅助服务器上不在线。数据库处于“恢复”状态。
更新: 我忘记提到的一点是,该过程的SPID通常高于50。根据我的阅读,低于50的SPID始终是系统进程。这是对的吗?
答案 0 :(得分:1)
您可以尝试使用此脚本,该脚本将终止指定数据库中的所有活动进程:
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本身。
答案 1 :(得分:0)
我找到了解决这个问题的方法(但不是问题的根源)。
我最终编写了一个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 $_
}
}
}
}