使用链接服务器是否影响事务隔离级别?相关技术咨询
链接服务器跨实例隔离级别交互问题
问题背景
我在Server B上通过链接服务器从Server A取数,存储过程foo代码如下:
-- in SERVER B CREATE PROC [foo] AS INSERT [Table] SELECT this, that FROM [LnkServer Server A].[database].[schema].[table];
已知Server B的is_read_committed_snapshot_on = 1,Server A未开启该配置,同时有两个衍生问题:
- 存储过程
foo会读取Server A的快照数据,还是等待事务完成? - 若在
foo中添加SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED语句,是否会读取Server A的未提交数据,还是保持原有读取行为?
另外,我计划将脚本修改为以下形式:
------------- In Server A -- CREATE PROC [bar] AS -- 此处设置本地隔离级别仅作示例,已知READ UNCOMMITTED并非始终适用及相关风险 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT this, that FROM [database].[schema].[table]; GO --------------- Server B -- CREATE PROC [foo] AS DECLARE @SQL NVARCHAR(MAX) = 'SELECT * FROM OPENQUERY([LnkServer Server A],''EXEC [database].[schema].[bar]'')'; INSERT [Table] EXEC sp_executesql @SQL; GO
我认为OPENQUERY能生成更优执行计划,且隔离级别更易管控,但现有大量类似第一个示例的查询,担心它们引发问题。查阅了诸多隔离级别资料,未找到链接服务器与隔离级别交互的内容,特此咨询。
问题解答
1. 初始场景的读取行为
Server B开启的READ_COMMITTED_SNAPSHOT仅作用于本地事务,对跨链接服务器访问Server A的查询无影响。跨实例查询的隔离级别由目标服务器(Server A)的配置和会话设置决定:
- Server A未开启快照隔离,默认隔离级别为
READ COMMITTED,因此当Server B的查询访问Server A时,若Server A上有未提交事务锁定目标表,该查询会等待锁释放,不会读取快照数据。
2. 添加READ UNCOMMITTED后的行为
在Server B的存储过程中设置SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED,该隔离级别会传递到链接服务器的查询会话。此时访问Server A的查询会以READ UNCOMMITTED级别执行,可读取Server A上的未提交数据,无需等待锁释放。
修改方案的优势
你提出的OPENQUERY调用目标实例存储过程的方案,确实具备两个核心优势:
- 更优执行计划:
OPENQUERY会将查询逻辑推送到Server A本地执行,避免把大量数据拉取到Server B后再处理,减少跨实例带宽占用;同时Server A可利用本地统计信息生成更高效的执行计划。 - 隔离级别管控更清晰:隔离级别直接在Server A的存储过程中设置,完全由目标实例的会话控制,不受发起端(Server B)的隔离级别或快照配置干扰,规则明确,排查问题更简单。
旧查询的风险提示
对于大量类似第一个示例的跨实例直接查询,需注意两点:
- 隔离级别依赖发起端会话设置和目标端默认配置,一旦发起端隔离级别被修改,会直接影响跨实例查询行为,易出现意外阻塞或脏读。
- 这类查询可能会将Server A的全表数据拉到Server B后再过滤,数据量大时会占用大量跨实例带宽,执行效率低下。
内容的提问来源于stack exchange,提问作者High Plains Grifter
相关产品推荐
相关产品推荐

