链接服务器“linkedserver”的“SQLNCLI11”返回消息“事务管理器已禁用对远程/网络事务的支持。”

AMM*_*MMH 2 sql-server linked-server availability-groups sql-server-2014

我在 SQL Server 2014 AG 组 (AG1) 中有一个数据库。- 两个节点。

在两个节点上,都设置了链接服务器。我正在从 AG 组 (AG1) 数据库的表中选择数据并插入链接服务器(来自另一个 AG 组(AG2)的数据库)。事务中唯一的语句是插入语句。它不是分布式事务。

为什么会出现以下错误?

链接服务器“LinkedserverListener”的 OLE DB 访问接口“SQLNCLI11”返回消息“事务管理器已禁用对远程/网络事务的支持。”。
消息 7391,级别 16,状态 2,第 2 行
由于链接服务器“LinkedServerListener”的 OLE DB 提供程序“SQLNCLI11”无法开始分布式事务,因此无法执行该操作。

示例代码如下。

Drop table #Myatran
Select 'ABC' name into #Myatran

DECLARE @pndstop_ps NVARCHAR(4000)
SET @pndstop_ps = 
N'
INSERT INTO '+ 'linkedserver'+'.DB.dbo.MyaTEST(Name) SELECT name FROM #Myatran
'
SET XACT_ABORT ON
BEGIN TRANSACTION

EXEC sp_executeSQl @pndstop_ps

SET XACT_ABORT OFF
Run Code Online (Sandbox Code Playgroud)

Han*_*non 6

SQL Server 2014 可用性组不支持分布式事务。

SQL Server 2016 对分布式事务的支持有限,但 SQL Server 2017 的支持最好

考虑使用 SQL Server 集成服务或 bcp 输入/输出,或其他一些用于提取-转换-加载或 ETL 操作的工具。

仅供参考,您可能没有意识到这一点,但是在INSERT INTO ...链接服务器上执行一个表会导致本地 SQL Server 为插入到目标表中的每一行执行一系列游标调用。

为了证明这一点,我创建了一个链接服务器并运行以下代码来设置一个简单的测试台。

首先,我们将在链接服务器的 tempdb 中创建一个表:

DECLARE @cmd nvarchar(max);
SET @cmd = 'IF OBJECT_ID(''dbo.InsertTest'', N''U'') IS NOT NULL
DROP TABLE dbo.InsertTest;
CREATE TABLE dbo.InsertTest
(
    id int NOT NULL PRIMARY KEY CLUSTERED
);';

EXEC [LinkedServer].tempdb.sys.sp_executesql @cmd;
Run Code Online (Sandbox Code Playgroud)

在这里,我在 tempdb 中创建一个本地表来保存一些行:

IF OBJECT_ID('dbo.InsertTest', N'U') IS NOT NULL
DROP TABLE dbo.InsertTest;CREATE TABLE dbo.InsertTest
(
    id int NOT NULL PRIMARY KEY CLUSTERED
);

INSERT INTO dbo.InsertTest (id)
SELECT ROW_NUMBER() OVER (ORDER BY c.object_id, c.column_id)
FROM sys.columns c;
Run Code Online (Sandbox Code Playgroud)

快速检查源表中是否有行:

SELECT CountOfRows = COUNT(1)
FROM dbo.InsertTest;
Run Code Online (Sandbox Code Playgroud)
???????????????
? 行数?
???????????????
? 990?
???????????????

在这里,我们将把本地源表中的行插入到远程链接服务器表中。我已经设置了在目标服务器上运行的跟踪,以便我们可以看到针对它发出的 T-SQL 语句。

INSERT INTO [LinkedServer].tempdb.dbo.InsertTest (ID)
SELECT it.ID
FROM dbo.InsertTest it;
Run Code Online (Sandbox Code Playgroud)

输出:

?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ????????????
? 设置 XACT_ABORT 关闭?
?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ????????????
? 声明@p1 整数?
? 设置@p1=NULL ?
? 声明@p2 bigint ?
? 设置@p2=NULL ?
? exec [sys].sp_getschemalock @p1 输出,@p2 输出,N'"tempdb"."dbo"."InsertTest"' ?
? 选择@p1,@p2 ?
? 声明@p1 整数?
? 设置@p1=NULL ?
? 声明@p3 int ?
? 设置@p3=229378?
? 声明@p4 int ?
? 设置@p4=294916?
? 声明@p5 int ?
? 设置@p5=NULL ?
? exec sp_cursoropen @p1 output,N'select * from "tempdb"."dbo"."InsertTest"',@p3 output,@p4 output,@p5 output ?
? 选择@p1、@p3、@p4、@p5?
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=1 ?
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=2 ?
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=3 ?
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=4 ?
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=5                                           
.
.
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=987 ?
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=988 ?
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=989 ?
? exec sp_cursor 180150027,4,0,N'[tempdb].[dbo].[InsertTest]',@id=990 ?
? exec [sys].sp_releaseschemalock 1 ?
? 执行 sp_cursorclose 180150027 ?
? 执行 sp_reset_connection ?
?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ????????????

但是,如果您从目标服务器运行插入,如下所示:

INSERT INTO dbo.InsertTest (ID)
SELECT it.ID
FROM [LinkedServer].tempdb.dbo.InsertTest it;
Run Code Online (Sandbox Code Playgroud)

您会在跟踪中看到这一点:

?????????????????????????????????????????????????????? ???????????????????????????
? 文本数据??
?????????????????????????????????????????????????????? ???????????????????????????
? 设置统计 XML 开启??
? ? 插入 dbo.InsertTest (ID) ?
? ? 选择它。ID?
? ? FROM [CP708-D377\MV].tempdb.dbo.InsertTest it; ?
? 设置统计 XML 关闭??
?????????????????????????????????????????????????????? ???????????????????????????

显然,在目标服务器而不是源服务器上运行插入是值得的。