问题描述
在异步触发器中,经触发后,消息没有发送不出去,于是去查询Service Broker 的传输队列,如果队列有数据,说明Service Broker 有消息在排队,可能在发送/接收中.如果队列空,Service Broker 没有待处理消息.
sql
SELECT * FROM sys.transmission_queue;
查询完发现所有的消息都堵塞着,没有发出来,而且提示异常信息
An exception occurred while enqueueing a message in the target queue. Error: 33009, State: 2. The database owner SID recorded in the master database differs from the database owner SID recorded in database 'his_bfyy'. You should correct this situation by resetting the owner of database 'xxx' using the ALTER AUTHORIZATION statement.
master 数据库记录的登录名 SID,与 xxx数据库记录的 owner_sid 不一致导致。
问题处理
这个错误 33009 通常是因为数据库是从另一台服务器恢复或迁移过来的,导致 master 数据库和用户数据库 xxx中记录的所有者安全标识符(SID)不一致。解决这个问题的核心方法是使用 ALTER AUTHORIZATION 语句,将数据库 xxx的所有者重新设置为一个有效的登录名(例如 sa)
sql
SELECT name, suser_sname(owner_sid) AS owner_name
FROM sys.databases
WHERE name = 'xxx';
执行授权语句
sql
ALTER AUTHORIZATION ON DATABASE::[xxx] TO [sa];
但是执行了很久,都没完成.可能的原因是有其他活动会话正在使用 xxx数据库,导致命令无法获得执行所需的独占访问权限。
查询阻塞会话
sql
SELECT
session_id,
blocking_session_id,
wait_type,
wait_time,
wait_resource,
command,
text
FROM sys.dm_exec_requests
CROSS APPLY sys.dm_exec_sql_text(sql_handle)
WHERE blocking_session_id > 0;
-- 查询进程session信息,包括睡眠的
SELECT
session_id,
status, -- 状态:Running / Sleeping / Background
login_name, -- 登录账号
host_name, -- 客户端机器名
program_name, -- 应用程序名称(如 SSMS、应用程序名)
client_interface_name, -- 连接协议
login_time, -- 登录时间
last_request_start_time, -- 最后一次请求开始时间
last_request_end_time, -- 最后一次请求结束时间
reads, writes, logical_reads,
cpu_time, memory_usage
FROM sys.dm_exec_sessions
-- WHERE session_id = 102;
WHERE session_id = 62;
-- 查询进行ssion的锁情况
SELECT
resource_type,
resource_database_id,
resource_description,
request_mode,
request_status
FROM sys.dm_tran_locks
WHERE request_session_id = 102;
如果结果中的 blocking_session_id 指向了你的 ALTER AUTHORIZATION 命令所在的SPID,说明有其他会话在阻塞它。
在结果中查找状态为 RUNNABLE 或 SUSPENDED 的会话,它们可能是导致阻塞的根源。
查询出来确实有被一些进程阻塞着.
有几种方式处理
(1) kill进程
sql
-- 生成 KILL 语句
SELECT
'KILL ' + CAST(l.request_session_id AS VARCHAR) + ';' AS KillCommand
FROM sys.dm_tran_locks l
INNER JOIN sys.dm_exec_sessions s ON l.request_session_id = s.session_id
WHERE l.resource_database_id = DB_ID('xxx')
AND l.resource_type = 'METADATA'
AND l.resource_description LIKE '%principal_id = 1%'
AND s.status = 'sleeping';
然后将这些进程kill调
(2) 将数据库设为单用户模式(最可靠)
可以强制断开所有其他连接,让你独占地执行命令
sql
USE master;
GO
ALTER DATABASE [xxx] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
-- 现在执行更改所有者的命令
ALTER AUTHORIZATION ON DATABASE::[xxx] TO [sa];
GO
-- 操作完成后,将数据库恢复为多用户模式
ALTER DATABASE [xxx] SET MULTI_USER;
GO
(3) 重启SQL Server服务
如果以上方法都无效,重启服务可以清除所有阻塞。