【问题标题】:AFTER INSERT trigger causes query execution to hang upAFTER INSERT 触发器导致查询执行挂起
【发布时间】:2018-05-25 07:33:24
【问题描述】:

在一个 ms sql 数据库中,我有一个名为 combo 的表,其中可以发生多个插入、更新和删除(当然也可以是单个)。在另一个名为 migrimi_temp 的表中,我以查询的形式跟踪这些更改(必须在 mysql 中执行才能获得相同结果的查询)。

例如,如果对 id > 50 的所有行执行删除查询,则应激活触发器以将以下查询存储到日志表中:

从 id > 50 的组合中删除;

因此,组合表中的这一删除查询将在日志表中产生一行。

但是,如果我有一个插入 2 行的插入查询,则应激活触发器以将每个插入存储到日志表中。因此,组合表中的这一插入查询将导致日志表中出现 2 个新行。

我打算将插入、更新和删除操作处理到单独的触发器中。我设法为单行插入/更新/删除编写触发器。然后我想到也可以执行多个操作。

这是我尝试在一个查询中处理多个插入的情况。在没有光标的情况下无法调整初始触发器后,我求助于使用光标。触发器已成功执行,但是当我执行插入(单行或多行)时,执行会无限期挂起,或者至少比合理的时间长。

USE [migrimi_test]
GO
/****** Object:  Trigger [dbo].[c_combo]    Script Date: 12/11/2017 5:33:46 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create TRIGGER [dbo].[u_combo]
ON [migrimi_test].[dbo].[combo]
AFTER INSERT
AS
BEGIN

    SET NOCOUNT ON
    DECLARE @c_id INT;
    DECLARE @c_name nvarchar(100);
    DECLARE @c_duration int;
    DECLARE @c_isavailable INT;

    DECLARE c CURSOR FOR
      SELECT id, name, duration, isvisible FROM inserted
    OPEN c
    FETCH NEXT FROM c INTO @c_id, @c_name, @c_duration, @c_isavailable
    WHILE @@FETCH_STATUS = 0

    INSERT INTO [migrimi_temp].[dbo].[sql_query] (query)
    VALUES ('INSERT INTO combo (id, name, duration, value, isavailable, createdAt, updatedAt) values ('+CAST(@c_id as nvarchar(50))+', '+'"'+@c_name+'"'+', 
    '+CAST(@c_duration as nvarchar(50))+', 1, '+CAST(@c_isavailable as nvarchar(50))+', Now(), Now());' )

    FETCH NEXT FROM c INTO @c_id, @c_name, @c_duration, @c_isavailable
    CLOSE c
    END
    DEALLOCATE c

GO

SQL server 版本是 2012。操作系统是 windows server 2008(尽管我怀疑这是否相关)。我主要是基于这两个资源:https://social.msdn.microsoft.com/Forums/sqlserver/en-US/40f5635c-9034-4e9b-8fd5-c02cec44ce86/how-to-let-trigger-act-for-each-row?forum=sqlgetstarted

How can I get a trigger to fire on each inserted row during an INSERT INTO Table (etc) SELECT * FROM Table2?

这是我正在努力实现的一个更大想法的一部分,直到 2 天前我完全不熟悉触发器。我正在努力平衡学习与在合理时间内完成,但做得不是很好

【问题讨论】:

  • 只要有足够的代码,就可以完成。我不禁认为将光标(已经不是最佳做法)放在触发器内(不是一个很好的做法)会导致很多心痛和糟糕的性能。

标签: tsql sql-server-2012 triggers


【解决方案1】:

众所周知,SQL Server 中的游标速度很慢。 您可以使用insert...select,而不是使用游标循环插入的表,这是一种基于集合的方法。它速度更快,并且是在 SQL 中工作的推荐方式:

CREATE TRIGGER [dbo].[u_combo]
ON [migrimi_test].[dbo].[combo]
AFTER INSERT
AS
BEGIN

    INSERT INTO [migrimi_temp].[dbo].[sql_query] (query)
    SELECT 'INSERT INTO combo (id, name, duration, value, isavailable, createdAt, updatedAt) values ('+CAST(id as nvarchar(50))+', "'+ name +'", 
        '+ CAST(duration as nvarchar(50)) +', 1, '+ CAST(isvisible as nvarchar(50))+ ', Now(), Now());'
    FROM inserted    

END

GO

【讨论】:

  • 我同意唱歌光标似乎是一个非常糟糕的主意。最初我尝试做这样的事情,但一定有一些糟糕的语法让我认为不会发生遍历所有行的迭代。
  • 很高兴为您提供帮助 ;-)
猜你喜欢
  • 1970-01-01
  • 2017-10-04
  • 1970-01-01
  • 2013-03-29
  • 2015-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多