我有一个从 SQL Server Ent 2012 到 PostgreSQL 9.3 的链接服务器设置和一个存储过程,从中提取 3 个过滤表并将每个表存储在一个临时表中。
在存储过程的末尾有一个带有许多左连接的最终查询,来自本地 SQL 数据库,它包括这 3 个临时表。
我已禁用“为 RPC 启用分布式事务的推广”。使用此存储过程的每 1/6 次或更多尝试都会失败,Web 服务器
Unknown Error Detected
System.Data.SqlClient.SqlException (0x80131904): The operation could not be performed because OLE DB provider "MSDASQL" for linked server "POSTGRESQL" was unable to begin a distributed transaction.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection
上的错误为: SQL Server 上没有错误。
链接服务器定义:
EXEC master.dbo.sp_addlinkedserver @server = N'POSTGRESQL', @srvproduct=N'PostgreSQL', @provider=N'MSDASQL', @datasrc=N'PostgreSQL'
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'POSTGRESQL',@useself=N'False',@locallogin=NULL,@rmtuser=N'xxxxxx',@rmtpassword='xxxxx'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'collation compatible', @optvalue=N'false'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'data access', @optvalue=N'true'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'dist', @optvalue=N'false'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'pub', @optvalue=N'false'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'rpc', @optvalue=N'true'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'rpc out', @optvalue=N'true'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'sub', @optvalue=N'false'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'connect timeout', @optvalue=N'0'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'collation name', @optvalue=null
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'lazy schema validation', @optvalue=N'false'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'query timeout', @optvalue=N'0'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'use remote collation', @optvalue=N'true'
EXEC master.dbo.sp_serveroption @server=N'POSTGRESQL', @optname=N'remote proc transaction promotion', @optvalue=N'false'
存储过程/查询 (非常简化抱歉)
ALTER PROCEDURE [dbo].[SP_Name]
@DateFrom DATETIME,
@DateTo DATETIME
AS
DECLARE @variableB int
SET @variableB= {some criteria}
IF (@variableB < 1000)
BEGIN
-- Passthrough to PG for a filtered table, instead of entire table grabbed via open query
IF OBJECT_ID('tempdb.dbo.#temp_table1', 'U') IS NOT NULL
DROP TABLE #temp_table1;
create table #temp_table1 (column1 int, column2 varchar(60))
DECLARE @TSQL varchar(max)
SET @TSQL = 'select c1, c2 from OpenQuery([POSTGRESQL],''
select c1, c2 from table1 t where
t.date>=''''' +CONVERT(VARCHAR(15),@DateFrom,102)+ '''''' + 't.date <=''''' +CONVERT(VARCHAR(15),@DateTo,102) + '''''' +'order by c1'')'
insert into #temp_table1
EXEC (@TSQL)
create clustered index temp_index1 on #temp_table1
(column1 asc)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
-- 2nd table passthrough to PG for a filtered table, instead of entire table grabbed via open query
IF OBJECT_ID('tempdb.dbo.#temp_table2', 'U') IS NOT NULL
DROP TABLE temp_table2;
create table #temp_table2 (column1 int, column2 varchar(60), column3 int)
SET @TSQL = 'select a, b, c from OpenQuery([POSTGRESQL],''
select a, b, c from table2 t where
t.date>=''''' +CONVERT(VARCHAR(15),@DateFrom,102)+ '''''' + 't.date <=''''' +CONVERT(VARCHAR(15),@DateTo,102) + '''''' +'order by a'')'
insert into #temp_table2
EXEC (@TSQL)
-- 3rd table passthrough to PG for a filtered table, instead of entire table grabbed via open query
IF OBJECT_ID('tempdb.dbo.#temp_table3', 'U') IS NOT NULL
DROP TABLE temp_table3;
create table #temp_table3 (column1 int, column2 varchar(60))
SET @TSQL = 'select a1, a2, a3 from OpenQuery([POSTGRESQL],''
select a1, a2, a3
from
table3 t
where
t.date>=''''' +CONVERT(VARCHAR(15),@DateFrom,102)+ '''''' + 't.date <=''''' +CONVERT(VARCHAR(15),@DateTo,102) + ''''''
{plus other filtering criteria} +'order by a1'')'
insert into #temp_table2
EXEC (@TSQL)
IF (@variableB < 1000)
BEGIN
select {many columns}
from {various local tables with left joins}
left join #temp_table1 on {conditions}
left join #temp_table2 on {conditions}
left join #temp_table3 on {conditions}
END
本地 DTC 属性
- 我认为正在发生的是,临时表中的 3 个开放查询正在分发,并且不知何故这不起作用。我承认我不太明白这一点——这超出了我的想象。我也知道启用“为 RPC 启用分布式事务的提升”会使失败更频繁地发生。
- 这再次工作了 5/6 次,失败了大约 1/6 次。所以我不确定发生了什么。
- 这是 PostgreSQL 上的只读事务 - 我不确定为什么要调用分布式事务。
编辑我在这里 看到这个问题,并认为我不应该遇到这个问题。
编辑 2 我可能在这里发现了一个重复的问题。
使用 ISOLATION LEVEL READ UNCOMMITTED 将 3 个临时表插入包装在一个事务中似乎已经停止升级到分布式事务并解决了我的间歇性问题。
这是一个重复的问题,最终给了我解决方案。也许,PostgreSQL ODBC 不支持分布式事务 - 由于 ACID 功能,在尝试使用临时表或尝试连接到远程数据库 3 次时,在链接服务器属性上禁用它们是不够的。