我有几个表格结构如下:
CREATE TABLE Person
(
PersonID INT PRIMARY KEY,
Name NVARCHAR(255),
LastUpdatedBy INT,
LastUpdatedDate DATETIME
);
CREATE TABLE Info
(
InfoID INT PRIMARY KEY,
PersonID INT,
Info NVARCHAR(255),
LastUpdatedBy INT,
LastUpdatedDate DATETIME
);
CREATE TABLE Setting
(
SettingID INT PRIMARY KEY,
PersonID INT,
Setting NVARCHAR(255),
LastUpdatedBy INT,
LastUpdatedDate DATETIME
);
我面临一个新的程序,如果Info或Setting表有任何更新,我需要对LastUpdatedBy和LastUpdatedDate列上的Person表进行相关更新。
首先想到的是创建一个SQL触发器,在Info或Setting表执行时自动更新Person表。但是请快速浏览几篇文章,说明应该避免使用SQL触发器,因为创建它时这是一个非常昂贵的过程,
虽然有些人建议更改应用程序代码。例如,
using (var db = new DbContext())
{
var result = db.Info.SingleOrDefault(x => x.InfoID == infoID);
if (result != null)
{
result.Info = "Some new value";
result.LastUpdatedBy = userID;
result.LastUpdatedDate = DateTime.UtcNow;
db.SaveChanges();
}
}
需要改变并变得像这样。
using (var db = new DbContext())
{
var result = db.Info.SingleOrDefault(x => x.InfoID == infoID);
if (result != null)
{
result.Info = "Some new value";
result.LastUpdatedBy = userID;
result.LastUpdatedDate = DateTime.UtcNow;
var person = db.Person.SingleOrDefault(x => x.PersonID == result.PersonID);
if (person != null)
{
person.LastUpdatedBy = result.LastUpdatedBy;
person.LastUpdatedDate = result.LastUpdatedDate;
}
db.SaveChanges();
}
}
实际上,应用程序代码很庞大,需要进行大量的代码修改。
假设有30多个表,每个表包含至少100k的记录。如果可以创建触发器,则如下所示:
CREATE TRIGGER TriggerName ON dbo.Info
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Person
SET LastUpdatedBy = INSERTED.LastUpdatedBy ,
LastUpdatedDate = INSERTED.LastUpdatedDate
FROM INSERTED
WHERE dbo.Person.PersonID = INSERTED.PersonID
END
GO
在这种情况下,是否应该真正避免使用SQL触发器?如果可以的话,请根据你的答案解释。任何替代解决方案都是受欢迎的,性能优先。
答案 0 :(得分:1)
此处触发器是最佳的(从性能角度来看);它就像在前端代码中对一堆行运行更新语句一样。我不明白为什么你认为会有性能损失。您的触发器代码看起来应该更像这样:
CREATE TRIGGER TriggerName ON dbo.Info
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Person
SET LastUpdatedBy = INSERTED.LastUpdatedBy ,
LastUpdatedDate = INSERTED.LastUpdatedDate
FROM dbo.Person
INNER JOIN
INSERTED
ON dbo.Person.PersonID = INSERTED.PersonID
END
GO
还有其他方法,例如创建一个更新事务中所有表的存储过程,或者更新前端数据访问层(如果您的前端有很多需要更新,则意味着它的结构错误:一个地方应该我有责任写这个表。如果你的前端代码有更新语句,那就好了......这是一个糟糕的设计)所以一个专门的类正确维护这两个表..
现在我说触发器是解决问题的最简单方法..它们并不是很受欢迎,但不是因为性能,而是因为它们开始增加令人困惑的后果......想象你作为ac#developer由于有限的数据库经验,不知道触发器是什么,而且你在抱怨“每次我更新这一张桌子时,其他所有27张桌子都会因魔术而改变!发生了什么事?我会发疯还是什么?” - 触发中断规则,例如“将所有数据更新代码保存在一个地方”,这就是为什么设计特定部件具有特定工作的系统的人不喜欢它们