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)
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 关闭?? ?????????????????????????????????????????????????????? ???????????????????????????
显然,在目标服务器而不是源服务器上运行插入是值得的。