2010-10-01 139 views
0

我有一个表中有一个很好的列(也许大约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... 

我通常喜欢第一种方法,因为它是更紧凑,似乎更地道。但是,速度问题时,我该怎么做?

回答

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是稳定不变的

+0

Gotcha!非常感谢,非常感谢...... – raven 2010-10-01 10:28:10

+0

只有当您没有空值或者您设置了ANSI_NULLS OFF时,这才会起作用 - 否则,涉及null的比较会产生'UNKNOWN',而不是True或False。 – 2010-10-04 15:35:29

+0

@大卫 - 呃,在这个问题中没有提到任何列是否可以为空,所以我没有在我的回答中解决这个问题。如果所有列都是不可空的,它将正常工作。 – 2010-10-04 15:48:27

-1

你为什么不使用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设置。

+1

嗯,它们在UPDATE触发器中同时存在。 – 2010-10-01 10:50:33