如果用户向表中插入行,我希望 SQL Server 执行一些额外的处理 - 但不是在用户事务的上下文中。
例如用户授予对文件夹的读取权限:
UPDATE Folders SET ReadAccess = 1
WHERE FolderID = 7
就用户而言,我希望这是原子操作的结束。实际上,我现在必须找到所有子文件和文件夹并给它们ReadAccess
。
EXECUTE SynchronizePermissions
这是一个潜在的冗长操作(超过 2 秒)。我希望这个冗长的操作“稍后”发生。它可以在 0 秒后发生,并且在碳单元有机会考虑它之前,异步更新已完成。
如果需要(即触发),我如何异步运行这个必需的操作?
理想的应该是:
CREATE TRIGGER dbo.Folders FOR INSERT, UPDATE, DELETE AS
EXECUTEASYNCHRONOUS SynchronizePermissions
或
CREATE TRIGGER dbo.Folders FOR INSERT, UPDATE, DELETE AS
EXECUTE SynchronizePermissions WITH(ASYNCHRONOUS)
现在这是作为触发器发生的:
CREATE TRIGGER dbo.Folders FOR INSERT, UPDATE, DELETE AS
EXECUTE SynchronizePermissions
并且用户每次对 Folders
表进行更改时都被迫等待 3 秒。
我考虑过在用户身上创建一个 Scheduled Task,每分钟运行一次,并检查 PermissionsNeedSynchronizing
标志:
CREATE TRIGGER dbo.Folders FOR INSERT, UPDATE, DELETE AS
UPDATE SystemState SET PermissionsNeedsSynchronizing = 1
计划任务二进制可以检查这个标志,如果标志打开则运行:
DECLARE @FlagValue int
SET @FlagValue = 0;
UPDATE SystemState SET @FlagValue = PermissionsNeedsSynchronizing+1
WHERE PermissionsNeedsSynchronizing = 1
IF @FlagValue = 2
BEGIN
EXECUTE SynchronizePermissions
UPDATE SystemState SET PermissionsNeedsSynchronizing = 0
WHERE PermissionsNeedsSynchronizing = 2
END
计划任务的问题是: - 它可以运行的最快速度是每 60 秒 - 它受到 polling 解决方案的影响 - 它需要一个可执行文件
我更喜欢 SQL Server 可以触发计划任务的方式:
CREATE TRIGGER dbo.Folders FOR INSERT, UPDATE, DELETE AS
EXECUTE SynchronizePermissionsAsychronous
CREATE PROCEDURE dbo.SynchronizePermissionsAsychronous AS
EXECUTE sp_ms_StartWindowsScheduledTask @taskName="SynchronousPermissions"
这个问题是:
- 没有sp_ms_StartWinodowsScheduledTask
系统存储过程
所以我正在寻找更好的解决方案。
更新:前面的例子是一个问题,五年来一直没有好的解决方案。 3 年前的一个没有好的解决方案的问题是我需要在插入/更新后更新元数据列的表。元数据在在线交易处理中计算时间太长,但我可以在 3 或 5 秒后出现:
CREATE TRIGGER dbo.UpdateFundsTransferValues FOR INSERT, UPDATE AS
UPDATE FundsTransfers
SET TotalOrderValue = (SELECT ....[snip]....),
TotalDropValue = (SELECT ....,[snip]....)
WHERE FundsTransfers.FundsTransferID IN (
SELECT i.FundsTransferID
FROM INSERTED i
)
我今天遇到的问题是一种在过渡插入或修改行后异步更新某些元数据的方法:
CREATE TRIGGER dbo.UpdateCDRValue FOR INSERT, UPDATE AS
UPDATE LCDs
SET CDRValue = (SELECT ....[snip]....)
WHERE LCDs.LCDGUID IN (
SELECT i.LCDGUID
FROM INSERTED i
)
更新 2:我考虑过创建 native 或托管 dll 并将其用作扩展存储过程。问题在于:
- 你不能编写二进制文件
- 我现在可以这样做了
最佳答案
使用队列表,并让不同的后台进程从队列中提取并处理它们。根据定义,触发器本身是用户事务的一部分——这正是他们经常被劝阻的原因(或者至少人们被警告不要在触发器中使用昂贵的技术)。
关于sql-server - SQL Server 从触发器触发异步更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7271922/