是否可以跨链接服务器在 SQLCLR 触发器之间共享 Local Temp table?
Is it possible to share Local Temp table between SQLCLR triggers across a Linked Server?
我需要为第三方产品实现分布式事务。我有两个 SQL 服务器和两个 SQLCLR 触发器。我想从另一个实例上的第二个触发器上下文访问本地 temp table 值。可能吗?
//Server 1
[Microsoft.SqlServer.Server.SqlTrigger (Name="SqlTrigger1", Target="Table1", Event="FOR INSERT")]
public static void SqlTrigger1 ()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
// Create #Temp table
// Insert some data
// Fire trigger Server 2 via Dblink
}
}
//Server 2
[Microsoft.SqlServer.Server.SqlTrigger (Name="SqlTrigger1", Target="Table1", Event="FOR INSERT")]
public static void SqlTrigger2 ()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
Read #Temp table ???
}
}
使用本地温度 table 不,但是使用全局温度 table(两个井号:##globalTemp
而不是 #temp
)您应该可以。话虽如此,这可能不是一个好主意,因为您永远不知道 ##globalTemp
table 是否存在。谁应该创建它?
There are two types of temporary tables: local and global. Local
temporary tables are visible only to their creators during the same
connection to an instance of SQL Server as when the tables were first
created or referenced. Local temporary tables are deleted after the
user disconnects from the instance of SQL Server. Global temporary
tables are visible to any user and any connection after they are
created, and are deleted when all users that are referencing the table
disconnect from the instance of SQL Server.
即时答案与SQLCLR无关。甚至在概念上不可能跨实例访问本地临时 table(或存储过程),因为与任何其他对象一样,它们对于创建它们的实例是本地的。当使用链接服务器时,无法访问调用会话,因此服务器 2 上的代码 运行 永远无法访问对服务器 1 上本地临时文件 table 的引用。
此外,虽然至少可以在实例之间访问全局临时 table(因为它们对所有会话可见),但仍需要在服务器 2 上创建一个额外的链接服务器指向服务器 1,因为那是全局临时 table 存在的地方。这有点混乱,并且与创建真正的 table 相比没有任何优势(除非您创建全局临时 table 以包含新创建的 GUID 值作为其名称的一部分,但是您仍然需要传输将 值传递给服务器 2,以便建立对服务器 1 的正确引用,这需要在动态 SQL).
中发生
来自 O.P 的澄清:
When user call query insert into dbo.Account (Name) values('something')
I intercept this with clr trigger and execute the same query on server2 insert into Server2.dbo.Account (Name) values('something')
and i need to shared context in this transaction for example a guid variable.
实例之间没有 "shard context" 这样的东西。两个地方需要的任何数据 and/or 值都需要传递到远程实例中。在这种情况下,您可以将数据作为 XML 打包在一个 NVARCHAR(MAX)
变量中,并在服务器 2 上执行存储过程,传入该 NVARCHAR(MAX)
值,将其转换为 XML
在存储过程中,并使用 .nodes()
解压缩它。然后,您还可以将单独的标量值作为其他参数传递给远程存储过程。例如:
DECLARE @DataToTransfer NVARCHAR(MAX),
@SomeGuid UNIQUEIDENTIFIER;
SET @DataToTransfer = (
SELECT *
FROM inserted
FOR XML RAW('row')
);
EXEC [LinkedServerName].[DatabaseName].[SchemaName].[StoredProcedureName]
@Param1 = @DataToTransfer,
@Param2 = @SomeGuid;
上面显示的方法效果很好。我用它每天将数百万行从 18 台生产服务器传输到一台存档服务器。与尝试在链接服务器上执行直接 DML / INSERT
语句相比,调用远程存储过程的锁定问题更少。此外,这种方法允许发送 table 数据(打包为 XML)和单个变量值(例如您提到的 Guid)。
远程存储过程——在上面示例代码的 EXEC
中引用——将在服务器 2 上本地执行,因此它可以创建一个本地临时 table,触发器远程 table 将有权访问或使用 SET CONTEXT_INFO or, if using SQL Server 2016 (or newer), use sp_set_session_context.
此外,您可能已经注意到,其中 none 与 SQLCLR 有任何关系。当您将使用 none 的 SQLCLR 触发器/对象的好处时,我认为没有理由在 SQLCLR 中引入额外的复杂性。
我需要为第三方产品实现分布式事务。我有两个 SQL 服务器和两个 SQLCLR 触发器。我想从另一个实例上的第二个触发器上下文访问本地 temp table 值。可能吗?
//Server 1
[Microsoft.SqlServer.Server.SqlTrigger (Name="SqlTrigger1", Target="Table1", Event="FOR INSERT")]
public static void SqlTrigger1 ()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
// Create #Temp table
// Insert some data
// Fire trigger Server 2 via Dblink
}
}
//Server 2
[Microsoft.SqlServer.Server.SqlTrigger (Name="SqlTrigger1", Target="Table1", Event="FOR INSERT")]
public static void SqlTrigger2 ()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
Read #Temp table ???
}
}
使用本地温度 table 不,但是使用全局温度 table(两个井号:##globalTemp
而不是 #temp
)您应该可以。话虽如此,这可能不是一个好主意,因为您永远不知道 ##globalTemp
table 是否存在。谁应该创建它?
There are two types of temporary tables: local and global. Local temporary tables are visible only to their creators during the same connection to an instance of SQL Server as when the tables were first created or referenced. Local temporary tables are deleted after the user disconnects from the instance of SQL Server. Global temporary tables are visible to any user and any connection after they are created, and are deleted when all users that are referencing the table disconnect from the instance of SQL Server.
即时答案与SQLCLR无关。甚至在概念上不可能跨实例访问本地临时 table(或存储过程),因为与任何其他对象一样,它们对于创建它们的实例是本地的。当使用链接服务器时,无法访问调用会话,因此服务器 2 上的代码 运行 永远无法访问对服务器 1 上本地临时文件 table 的引用。
此外,虽然至少可以在实例之间访问全局临时 table(因为它们对所有会话可见),但仍需要在服务器 2 上创建一个额外的链接服务器指向服务器 1,因为那是全局临时 table 存在的地方。这有点混乱,并且与创建真正的 table 相比没有任何优势(除非您创建全局临时 table 以包含新创建的 GUID 值作为其名称的一部分,但是您仍然需要传输将 值传递给服务器 2,以便建立对服务器 1 的正确引用,这需要在动态 SQL).
中发生来自 O.P 的澄清:
When user call query
insert into dbo.Account (Name) values('something')
I intercept this with clr trigger and execute the same query on server2insert into Server2.dbo.Account (Name) values('something')
and i need to shared context in this transaction for example a guid variable.
实例之间没有 "shard context" 这样的东西。两个地方需要的任何数据 and/or 值都需要传递到远程实例中。在这种情况下,您可以将数据作为 XML 打包在一个 NVARCHAR(MAX)
变量中,并在服务器 2 上执行存储过程,传入该 NVARCHAR(MAX)
值,将其转换为 XML
在存储过程中,并使用 .nodes()
解压缩它。然后,您还可以将单独的标量值作为其他参数传递给远程存储过程。例如:
DECLARE @DataToTransfer NVARCHAR(MAX),
@SomeGuid UNIQUEIDENTIFIER;
SET @DataToTransfer = (
SELECT *
FROM inserted
FOR XML RAW('row')
);
EXEC [LinkedServerName].[DatabaseName].[SchemaName].[StoredProcedureName]
@Param1 = @DataToTransfer,
@Param2 = @SomeGuid;
上面显示的方法效果很好。我用它每天将数百万行从 18 台生产服务器传输到一台存档服务器。与尝试在链接服务器上执行直接 DML / INSERT
语句相比,调用远程存储过程的锁定问题更少。此外,这种方法允许发送 table 数据(打包为 XML)和单个变量值(例如您提到的 Guid)。
远程存储过程——在上面示例代码的 EXEC
中引用——将在服务器 2 上本地执行,因此它可以创建一个本地临时 table,触发器远程 table 将有权访问或使用 SET CONTEXT_INFO or, if using SQL Server 2016 (or newer), use sp_set_session_context.
此外,您可能已经注意到,其中 none 与 SQLCLR 有任何关系。当您将使用 none 的 SQLCLR 触发器/对象的好处时,我认为没有理由在 SQLCLR 中引入额外的复杂性。