You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server 2019中无表查询为何成为阻塞主查询?

排查建议:看似无害的查询引发SQL Server阻塞的原因分析

一、会话资源持有异常

  • 未终止的残留事务:即使当前执行的是SELECT SUSER_NAME(), SUSER_ID();这类无表访问的查询,会话可能之前执行过修改类操作(如INSERT/UPDATE/DELETE)但未提交或回滚事务,导致锁资源一直被持有。此时该会话会成为阻塞源头,杀掉进程后事务自动回滚,锁释放。可通过sys.dm_tran_session_transactions查询阻塞会话是否存在活跃事务,用DBCC INPUTBUFFER(<阻塞PID>)查看会话历史执行语句。
  • 客户端结果未取完:像查询报表的SELECT AbsoluteName FROM REPORT WHERE ReportName = 'namehere',看似已执行完成,但如果客户端程序未完整读取结果集,SQL Server会话会一直处于等待状态(常见等待类型ASYNC_NETWORK_IO),持续占用会话资源并引发阻塞。可通过sys.dm_exec_requests查看阻塞会话的wait_type确认。

二、环境与配置差异

  • 隔离级别或快照设置不同:该客户数据库可能启用了特殊隔离级别(如SERIALIZABLE),或未开启READ_COMMITTED_SNAPSHOT,导致即使简单查询也会触发更长时间的锁持有或范围锁。对比其他正常客户的sys.databases中is_read_committed_snapshot_on等参数,以及会话级的SET TRANSACTION ISOLATION LEVEL配置。
  • 服务器资源瓶颈:客户服务器存在CPU、内存或磁盘IO瓶颈时,SQL Server处理会话的速度变慢,即使简单查询也会因资源争抢导致排队阻塞。比如内存不足引发频繁页交换、磁盘IO过高导致锁释放延迟,可通过sys.dm_os_performance_counters监控CPU使用率、页交换率、磁盘读写等待指标。

三、应用程序层面问题

  • 连接池资源泄漏:应用的连接池配置错误,或代码中未正确释放数据库连接,导致会话长期处于打开状态,残留的事务或资源未被清理。比如连接被复用前未完成事务提交/回滚,后续请求被该会话阻塞。
  • 隐式事务未关闭:应用可能开启了SET IMPLICIT_TRANSACTIONS ON,执行完查询后未显式提交事务,导致会话一直持有事务资源。可通过sys.dm_exec_sessions的is_implicit_transaction_on字段检查阻塞会话的隐式事务状态。

四、SQL Server内部异常

  • 补丁或版本差异:该客户的SQL Server 2019可能未安装最新累积更新,存在会话资源泄漏的已知bug,导致会话无法正常释放资源。对比其他正常客户的补丁版本,尝试安装对应最新补丁验证。
  • 扩展组件残留:如果阻塞会话之前调用过扩展存储过程、CLR程序或第三方插件,可能存在资源未释放的情况,后续执行简单查询时仍持有资源引发阻塞。可通过sys.dm_exec_sessions的last_executed_procedure字段查看会话历史执行的组件。

即时排查操作

当阻塞发生时,立即执行以下SQL收集关键信息:

-- 查看完整阻塞链及会话状态
SELECT 
    r.blocking_session_id,
    r.session_id,
    r.wait_type,
    r.wait_time,
    s.transaction_isolation_level,
    s.is_implicit_transaction_on,
    COALESCE(qt.text, '无SQL文本') AS last_executed_sql
FROM sys.dm_exec_requests r
JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) qt
WHERE r.blocking_session_id <> 0
UNION ALL
SELECT 
    0 AS blocking_session_id,
    s.session_id,
    s.wait_type,
    s.wait_time,
    s.transaction_isolation_level,
    s.is_implicit_transaction_on,
    COALESCE(qt.text, '无SQL文本') AS last_executed_sql
FROM sys.dm_exec_sessions s
OUTER APPLY sys.dm_exec_sql_text(s.sql_handle) qt
WHERE s.session_id IN (SELECT blocking_session_id FROM sys.dm_exec_requests WHERE blocking_session_id <> 0);

-- 检查阻塞会话的活跃事务
SELECT 
    s.session_id,
    t.transaction_id,
    t.transaction_begin_time,
    CASE t.transaction_state
        WHEN 0 THEN '未初始化'
        WHEN 1 THEN '活跃'
        WHEN 2 THEN '已提交'
        WHEN 3 THEN '正在回滚'
        WHEN 4 THEN '已回滚'
    END AS transaction_state
FROM sys.dm_tran_session_transactions s
JOIN sys.dm_tran_transactions t ON s.transaction_id = t.transaction_id
WHERE s.session_id IN (SELECT blocking_session_id FROM sys.dm_exec_requests WHERE blocking_session_id <> 0);

内容的提问来源于stack exchange,提问作者PG Tuser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 03:03:14