如何优化触发器?

时间:2017-05-13 06:35:19

标签: sql sql-server tsql

CREATE TRIGGER T 
ON TABLE_2 
AFTER INSERT 
AS
     DECLARE @bought_t int,
             @name_t varchar(20)

     SELECT @name_t = name_t 
     FROM inserted

     SELECT @bought_t = bought_t 
     FROM TABLE_1 
     WHERE name_t = @name_t

     IF @bought_t < 100 
     BEGIN
         UPDATE TABLE_1
         SET bought_t = @bought_t + 1
         WHERE TABLE_1.name_t = @name_t
     END
     ELSE 
        ROLLBACK TRANSACTION

我在'TABLE_2'中插入后发生更新的列(TABLE_1)应该保持50到100之间的值。所以我问如果这个触发器是专业的,尽可能优化?或者我有一些可能导致错误/安全问题的缺陷。

1 个答案:

答案 0 :(得分:1)

基本上,您需要将触发器完全重写为基于集合,并且能够在Inserted伪表中使用多行

幸运的是,这也让我更容易 - 在我看来 - 尝试这样的事情:

CREATE TRIGGER T 
ON TABLE_2 
AFTER INSERT 
AS
    UPDATE T1
    SET bought_t = bought_t + 1
    FROM TABLE_1 T1
    INNER JOIN Inserted i ON i.name_t = T1.name_t
    WHERE T1.bought_t < 100

更新:演示证明这有效:

-- create the two tables
CREATE TABLE TABLE_2 (ID INT NOT NULL IDENTITY(1,1), ProdName VARCHAR(50))
CREATE TABLE TABLE_1 (ProdName VARCHAR(50), Bought INT)
GO

-- create trigger on "TABLE_2" to update "TABLE_1"    
CREATE TRIGGER T2Insert
ON TABLE_2
AFTER INSERT
AS
    UPDATE T1
    SET Bought = Bought + 1
    FROM TABLE_1 T1
    INNER JOIN Inserted i ON T1.ProdName = i.ProdName
    WHERE T1.Bought < 100
GO

-- initialize TABLE_1 with some seed data
INSERT INTO dbo.TABLE_1 (ProdName, Bought)
VALUES ( 'Prod1', 0), ('Prod2', 20), ('Prod3', 40), ('Prod4', 40), ('Prod100', 100)

-- insert new values into TABLE_2
INSERT INTO dbo.TABLE_2 (ProdName)
VALUES  ('Prod1'), ('Prod100'), ('Prod2'), ('Prod4')

-- get data to check
SELECT * FROM dbo.TABLE_1

这会呈现输出:

enter image description here

您可以很容易地看到:

  • 插入的Prod1,Prod2,Prod4导致更新值Bought
  • 插入的Prod100 导致更新Bought

更新#2:如果您需要一次插入多个相同的值,则需要稍微增强触发器,如下所示:

CREATE TRIGGER T2Insert
ON TABLE_2
AFTER INSERT
AS
    -- declare table variable to hold names and update counts 
    DECLARE @UpdateCount TABLE (Name VARCHAR(50), UpdCount INT)

    -- from the "Inserted" table, determine which names are being
    -- inserted how many times using GROUP BY    
    INSERT INTO @UpdateCount (Name, UpdCount)
        SELECT ProdName, COUNT(*)
        FROM Inserted
        GROUP BY ProdName

    -- now join to this temporary table, and update as many times
    -- as needed (instead of +1 for all cases)
    UPDATE T1
    SET Bought = Bought + uc.UpdCount
    FROM TABLE_1 T1
    INNER JOIN @UpdateCount uc ON uc.Name = T1.ProdName
    WHERE T1.Bought < 100
GO