为什么对具有INSTEAD OF UPDATE触发器的表进行UPDATE似乎会执行聚集索引插入以及聚集索引更新?


10

我将从一个非常简单的示例开始:两个表都具有相同的模式,它们都聚集在PK上,但是其中一个具有INSTEAD OF UPDATE触发器:

CREATE TABLE Standard
(
    PK  UNIQUEIDENTIFIER PRIMARY KEY CLUSTERED,
    V   INT NOT NULL
)
GO

CREATE TABLE InsteadOf
(
    PK  UNIQUEIDENTIFIER PRIMARY KEY CLUSTERED,
    V   INT NOT NULL
)
GO

INSERT Standard (PK, V) VALUES ('1E58B555-B073-471E-B576-4B09C8E18976', 0)
INSERT InsteadOf (PK, V) VALUES ('1E58B555-B073-471E-B576-4B09C8E18976', 0)
GO

CREATE TRIGGER TR_InsteadOf_Update ON InsteadOf INSTEAD OF UPDATE
AS
BEGIN
    DECLARE @PK UNIQUEIDENTIFIER
    DECLARE @V INT
    DECLARE @cursor CURSOR
    SET @cursor = CURSOR FOR SELECT PK, V FROM Inserted
    OPEN @cursor

    FETCH NEXT FROM @cursor INTO @PK, @V
    WHILE @@FETCH_STATUS = 0
    BEGIN
        UPDATE InsteadOf SET
            V = @V
        WHERE PK = @PK

        FETCH NEXT FROM @cursor INTO @PK, @V
    END
    CLOSE @cursor
    DEALLOCATE @cursor

END
GO

如果查看查询计划以针对标准表进行更新,则会得到预期的聚集索引更新:

UPDATE Standard SET
    V = 1
    WHERE PK = '1E58B555-B073-471E-B576-4B09C8E18976'

在此处输入图片说明

但是,如果我使用触发器对表执行类似的更新,则会得到似乎是聚集索引插入以及聚集索引更新的内容:

UPDATE InsteadOf SET
    V = 1
    WHERE PK = '1E58B555-B073-471E-B576-4B09C8E18976'

在此处输入图片说明

为什么是这样?我可以看到稍后在此查询计划(查询#4)中期望的聚集索引更新,但是为什么在查询#1处得到此额外的插入?

Answers:


10

一个INSTEAD OF触发商店,就在一个隐藏的工作表*影响的行的副本。这是您看到的聚集索引插入。触发器主体从该工作表中读取*,并且触发器中的任何数据更改都使用“正常”运算符(在您的示例中为“聚集索引更新”)。


*当构造执行计划的用户可见形式时,查询处理器在内部重命名工作表。当写它,它被重命名为目标基表,读取数据时,它被更名为inserteddeleted或多或少的人希望在一个触发器看到。

有关更多详细信息,请参阅我的文章INSTEAD OF触发器的有趣内容

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.