【问题标题】:What comparison method is better?什么比较方法更好?
【发布时间】:2010-10-04 23:52:22
【问题描述】:

我在一个表中有一个触发器,其中包含大量列(可能大约 100 个)和相当多的更新(对于“很多”的某些定义)。 如果某些字段中的任何一个发生了更改,则触发器会在另一个表中插入一些数据。

出于显而易见的原因,我希望此触发器尽可能快地运行。进行比较的最佳方法是什么? 现在我有这些:

IF NOT EXISTS (SELECT * FROM Inserted i, Deleted d WHERE 
    i.Fld1 = d.Fld1 AND i.Fld2 = d.Fld2 AND
    i.Fld3 = d.Fld3 AND i.Fld4 = d.Fld4 AND
    i.Fld5 = d.Fld5 AND i.Fld6 = d.Fld6 AND
    i.Fld7 = d.Fld7)     
    THEN ...

IF ((SELECT Fld1 FROM Inserted) <> (SELECT Fld1 FROM Deleted) OR
    (SELECT Fld2 FROM Inserted) <> (SELECT Fld2 FROM Deleted) OR
    (SELECT Fld3 FROM Inserted) <> (SELECT Fld3 FROM Deleted) OR
    (SELECT Fld4 FROM Inserted) <> (SELECT Fld4 FROM Deleted) OR
    (SELECT Fld5 FROM Inserted) <> (SELECT Fld5 FROM Deleted) OR
    (SELECT Fld6 FROM Inserted) <> (SELECT Fld6 FROM Deleted) OR
    (SELECT Fld7 FROM Inserted) <> (SELECT Fld7 FROM Deleted))
THEN...

我通常更喜欢第一种方法,因为它更紧凑并且看起来更惯用。但是,当速度成为问题时,我应该怎么做?

【问题讨论】:

    标签: sql-server tsql optimization triggers


    【解决方案1】:

    第二个版本完全无法用于多行更新,因此仅出于这个原因,我会做第一个的变体:

    INSERT INTO ANotherTable (Column1, COlumn2, /* Etc */)
    SELECT i.Column1,d.Column1, /* Other COlumns */
    FROM
        inserted i
            inner join
        deleted d
            on
                i.Fld1 = d.Fld1 and /* For each column in PK */
                i.Fld2 <> d.Fld2 /* For each non-PK column */
    

    假设PK是稳定不变的

    【讨论】:

    • 这只有在你没有空值或 SET ANSI_NULLS OFF 时才有效 - 否则,涉及空值的比较将产生 UNKNOWN,而不是 True 或 False。
    • @David - 嗯,问题中没有提到任何列是否可以为空,所以我没有在回答中解决这个问题。如果所有列都不可为空,它将正常工作。
    【解决方案2】:

    您为什么不使用IF UPDATE(Column1,Column2,...) 测试更改的列,这将让您知道是否有任何您感兴趣的列发生了更改。有关UPDATE() 函数的详细信息,请参阅http://msdn.microsoft.com/en-us/library/ms187326.aspx

    如果 PK 已被修改,您也可以使用它,而在 inserteddeleted 之间进行比较,您尝试使用它的方式将错过对 PK 的更改。

    除非您在比较之前SET ANSI_NULLS OFF,否则涉及测试所有字段不等式的解决方案将失败。

    例如:

    create table table1 ( a varchar(4), b varchar(4) null)
    create table table2 ( a varchar(4), b varchar(4) null)
    go
    
    insert into table1 ( a, b ) select 'asdf', null
    insert into table2 ( a, b ) select 'asdf', 'zzzz'
    
    --Expect no results
    
    select *
    from table1
    inner join table2
    on a.a = b.a
    where a.b <> b.b
    
    set ansi_nulls off
    
    --Expect 1 result
    
    select *
    from table1
    inner join table2
    on a.a = b.a
    where a.b <> b.b
    

    当然,您可以进行额外的测试,而不是使用ansi_nulls 选项,但如果您对许多字段执行此操作,那将变得特别疯狂。另外:您必须在创建触发器之前set ansi_nulls off - 您无法在触发器内部打开和关闭它,因此整个事物必须具有相同的ansi_nulls 设置。

    【讨论】:

    • 嗯,它们确实同时存在于 UPDATE 触发器中。
    猜你喜欢
    • 2014-10-06
    • 1970-01-01
    • 2012-10-31
    • 2018-11-12
    • 2012-05-31
    • 1970-01-01
    • 2017-07-01
    • 2016-05-10
    • 1970-01-01
    相关资源
    最近更新 更多