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

为何SELECT查询被INSERT阻塞?读写不阻塞的认知困惑求助

为什么你的SQL Server读写操作会互相阻塞?

嗨,这个问题其实挺典型的,咱们来拆解一下你遇到的情况:

你的认知偏差在哪里?

你之前认为“写入操作不会阻塞读取操作(反之亦然)”,这个假设不完全正确——SQL Server的锁机制和事务隔离级别共同决定了读写是否会互相阻塞,默认场景下并不是完全无阻塞的。

你的场景里阻塞发生的原因

咱们一步步看你的操作:

  1. 你开启了IMPLICIT_TRANSACTIONS,这意味着执行INSERT后事务不会自动提交,锁会一直被持有,直到你显式执行COMMIT或ROLLBACK。
  2. 当你执行INSERT时,SQL Server会对插入的行加上排他锁(X锁),这种锁会阻止其他事务对该行进行读取或写入操作(在默认隔离级别下)。
  3. 默认情况下,SQL Server的事务隔离级别是READ COMMITTED,这个级别要求SELECT语句必须读取已提交的数据,所以它会等待行上的排他锁释放后才能继续执行——哪怕你换了sa账户,锁的规则是全局生效的,所以还是会被阻塞。

解决方法

针对你的场景,有几个可行的解决方向:

1. 及时提交/回滚未完成的事务

这是最直接的方法,在执行完INSERT后,立即执行:

COMMIT; -- 或者 ROLLBACK; 如果不需要保留插入的数据

释放锁之后,SELECT语句就能立即返回结果了。

2. 修改事务隔离级别

如果你需要在不提交写事务的情况下读取数据,可以调整隔离级别:

  • 允许脏读(READ UNCOMMITTED):这个级别会跳过锁检查,直接读取未提交的数据,适合对数据一致性要求不高的场景:
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    SELECT * FROM [dbo].[MyTab];
    
  • 使用快照隔离(SNAPSHOT ISOLATION):这个级别会通过行版本存储,读取事务开始时的数据快照,完全不会被写操作阻塞,同时也能避免脏读:
    首先开启数据库的快照隔离支持:
    ALTER DATABASE [testdb] SET ALLOW_SNAPSHOT_ISOLATION ON;
    
    然后在查询会话中设置隔离级别:
    SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
    SELECT * FROM [dbo].[MyTab];
    

3. 避免依赖隐式事务

IMPLICIT_TRANSACTIONS很容易导致事务长时间未提交,除非你有明确的业务需求,否则建议关闭它,改用显式的BEGIN TRANSACTION、COMMIT来管理事务,这样能更清晰地控制锁的生命周期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:37:50