SQL Server触发器插入导致锁定直到提交

时间:2016-09-12 22:18:22

标签: sql sql-server triggers transactions deadlock

通过触发器锁定相关表格时遇到问题。

我正在插入表tCatalog(这有一个触发器,只需在另一个表tSearchQueue中插入一条记录)。 tCatalog的插入位于一个事务中,该事务具有许多其他函数,有时需要几秒钟。但是,tSearchQueue表将被锁定,直到可以提交事务。有没有办法避免这种情况?

INSERT INTO [dbo].[tSearchQueue] (Processed, SQL, sys_CreateDate) 
    SELECT      
        0, 'Test ' + cast(CatalogID as varchar(10)), getdate()
    FROM        
        inserted 


BEGIN TRAN t1
    DECLARE @catalogid int

    INSERT INTO tCatalog (ProgramID, sys_CreatedBy, ItemNumber, Description, UOMID) 
    VALUES (233, 1263, 'brian catalog4', 'brian catalog4', 416)

    SELECT @catalogid = SCOPE_IDENTITY()

    INSERT INTO tCustomAttributeCatalog (CatalogID, CustomAttributeID, DefaultValue, DefaultValueRead, sys_CreatedBy) 
    VALUES (@catalogid, 299, 'No', 'No', 1263)

    INSERT INTO tCustomAttributeCatalog (CatalogID, CustomAttributeID, DefaultValue, DefaultValueRead, sys_CreatedBy) 
    VALUES (@catalogid, 300, null, null, 1263)

COMMIT TRAN t1

1 个答案:

答案 0 :(得分:0)

看起来您有一个后台进程,希望收到更改通知,以便进行某种重新索引。如果情况不一定错误它被阻止,那么如果交易没有提交,那么它无论如何都不应该为它编制索引。

所以顺序是:

  • 开始交易
  • 插入tCatalog
    • 触发器插入tSearchQueue
  • 插入一些其他表格
  • 执行长时间运行
  • 提交交易。

问题是另一个进程想要读取tSearchQueue但是因为它被锁定而不能。

选项1:批量执行后台操作。

如果进程落后,因为它几乎没有机会读取表,那么一次读取多行可以解决问题。即每当它有机会读取队列时,它应该读取许多行,一次处理它们,然后将它们全部标记为一起完成(或根据具体情况删除它们)。

选项2:如果可能,首先执行长时间运行操作:

  • 开始交易
  • 执行长时间运行
  • 插入tCatalog
    • 触发器插入tSearchQueue
  • 插入一些其他表格
  • 提交交易

其他进程现在发现tSearchQueue仅在短时间内被锁定。 请注意,如果长时间运行的操作是文件副本,则可以使用CopyFileTransacted将这些操作包含在事务中,或者可以在" catch"中回滚这些副本。声明如果操作失败。

选项3:后台进程避免锁定

如果其他进程主要尝试读取表,则快照隔离可以解决您的问题。这将仅返回已提交的行,因为它们存在于该时间点。结合行级锁定可以解决您的问题。

或者,后台进程可能会读取NOLOCK提示(脏读)。这可能导致从稍后回滚的事务中读取数据。但是,如果在单独的步骤中验证数据(例如,您只是编写需要重新索引的对象的标识符),则这不一定是个问题。如果索引过程可以处理不再存在的条目,或者实际上没有变化的条目,那么虚假读取就不重要了。