Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 在我的表触发器中记录更改的更有效方法_Sql_Sql Server_Database_Performance_Tsql - Fatal编程技术网

Sql 在我的表触发器中记录更改的更有效方法

Sql 在我的表触发器中记录更改的更有效方法,sql,sql-server,database,performance,tsql,Sql,Sql Server,Database,Performance,Tsql,当前,每个表的触发器对于表中的每个字段都是这样的: ALTER TRIGGER [dbo].[trg_Statement] ON [dbo].[tbl_Statement] FOR INSERT, UPDATE, DELETE AS BEGIN SET NOCOUNT ON INSERT INTO tbl_ChangeLog(TableName, ID, FieldName, OldValue, NewValue) SELECT 'Statement

当前,每个表的触发器对于表中的每个字段都是这样的:

ALTER TRIGGER [dbo].[trg_Statement] ON [dbo].[tbl_Statement]
FOR INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON
    INSERT INTO tbl_ChangeLog(TableName, ID, FieldName, OldValue, NewValue)
       SELECT  
          'Statement', CU.id, 'id', deleted.id,inserted.id
       FROM
          tbl_Statement CU
       LEFT JOIN 
          inserted on CU.id = inserted.id
       LEFT JOIN 
          deleted on CU.id = deleted.id
       WHERE
          (inserted.id is not null or deleted.id is not null)
          AND IsNull(inserted.id,'') <> IsNull(deleted.id,'')

    INSERT INTO tbl_ChangeLog(TableName, ID, FieldName, OldValue, NewValue)
       SELECT 
          'Statement', CU.id, 'idAccount', deleted.idAccount,inserted.idAccount
       FROM
          tbl_Statement CU
       LEFT JOIN 
          inserted on CU.id = inserted.id
       LEFT JOIN 
          deleted on CU.id = deleted.id
       WHERE
          (inserted.id is not null or deleted.id is not null)
          AND IsNull(inserted.idAccount,'') <> IsNull(deleted.idAccount,'')

    INSERT INTO tbl_ChangeLog(TableName, ID, FieldName, OldValue, NewValue)
       SELECT 
          'Statement', CU.id, 'OpeningBalance', deleted.OpeningBalance,inserted.OpeningBalance
       FROM
          tbl_Statement CU
       LEFT JOIN 
          inserted on CU.id = inserted.id
       LEFT JOIN 
          deleted on CU.id = deleted.id
       WHERE
          (inserted.id is not null or deleted.id is not null)
          AND IsNull(inserted.OpeningBalance,'') <> IsNull(deleted.OpeningBalance,'')
   ...
在[dbo].[tbl_语句]上更改触发器[dbo].[trg_语句]
对于插入、更新、删除
作为
开始
不计较
插入tbl_变更日志(表名、ID、字段名、OldValue、NewValue)
挑选
“语句”,CU.id,“id”,删除的.id,插入的.id
从…起
tbl_声明CU
左连接
插入CU.id=插入的CU.id
左连接
已在CU.id上删除=已删除.id
哪里
(inserted.id不为null或deleted.id不为null)
和IsNull(inserted.id“”)IsNull(deleted.id“”)
插入tbl_变更日志(表名、ID、字段名、OldValue、NewValue)
挑选
“语句”,CU.id,“idAccount”,已删除。idAccount,已插入。idAccount
从…起
tbl_声明CU
左连接
插入CU.id=插入的CU.id
左连接
已在CU.id上删除=已删除.id
哪里
(inserted.id不为null或deleted.id不为null)
IsNull(插入的.idAccount“”)IsNull(删除的.idAccount“”)
插入tbl_变更日志(表名、ID、字段名、OldValue、NewValue)
挑选
“语句”,CU.id,“OpeningBalance”,已删除。OpeningBalance,已插入。OpeningBalance
从…起
tbl_声明CU
左连接
插入CU.id=插入的CU.id
左连接
已在CU.id上删除=已删除.id
哪里
(inserted.id不为null或deleted.id不为null)
和IsNull(inserted.OpeningBalance“”)IsNull(deleted.OpeningBalance“”)
...

然而,这是非常昂贵的,特别是当有很多字段时,有人能提出一种更有效的方法来跟踪对变更日志的更改吗?

我有时会创建一个与我要记录的表相同的表,除了添加一个新的标识主键和一个日期时间字段来跟踪更改发生的时间。然后,每当原始表发生更改时,我都会将更改的整行加上当前日期时间插入跟踪表

它的优点是易于实现,并允许在需要时回滚到以前的一组值。如果您想查看全部历史记录,它还允许轻松连接到当前行(如果您经常这样做,请记住索引)。此外,在您的情况下,它只是一个插入,除了获取正确的行之外,没有任何逻辑。缺点是每次更改时都会存储所有字段,您必须维护两个表

显然,您可以减少您不想跟踪的字段,或者以其他更符合您需要的方式对此进行修改。例如,如果行被删除,您可能希望在跟踪表中保留一个额外字段


为了查看旧值和新值,您只需在表中的日期前向后查看它的更改时间。

我同意Madison的观点,您审计表中包含整个记录的一行将更有用,性能也更高。基表越宽,情况就越是如此。就你而言:

CREATE TRIGGER IUD_Statement_Audit
ON dbo.tbl_Statement AFTER INSERT, UPDATE, DELETE
AS BEGIN

  IF (@@rowCount = 0) RETURN;

  SET NOCOUNT ON;

  INSERT INTO dbo.tbl_Statement_AUDIT
    (id, idAccount, OpeningBalance, insertedOrDeleted, modTime, modId)
  SELECT id, idAccount, OpeningBalance, 'D', GETDATE(), USER_NAME() FROM DELETED
  UNION ALL
  SELECT id, idAccount, OpeningBalance, 'I', GETDATE(), USER_NAME() FROM Inserted

END
这种方法有很多好处,包括:轻松地在id列上联接,以查看所有表的所有更改和触发器,并将它们变成复制/粘贴练习。一般来说,RDBMS在使用较宽的表(一条记录包含所有列)和较少的记录时会表现得更好,而不是使用较窄的[?]表(每列更改一条记录)。您当前的方法将为插入、删除和更新的每个记录创建三个记录


通过按
modTime desc、insertedOrDeleted desc
对审核表进行排序并执行反向操作,可以回滚到过去的一点。。。尽可能地返回。

我认为中描述的方法更短、更快、更清晰。它不存储更改的“类型”,例如插入、更新或删除,而是创建一个名为的结构。插入是没有先前“版本”的行,删除是没有子提示“版本”的行,中间行是更新

它的优点是,在特定时间点检索特定实体的数据更容易、更自然


事实上,很容易得到整个表在特定时间点的状态。如果表格变得凌乱,并且需要从给定的“安全”时间点恢复数据,则此选项非常有用。

学到的经验教训…需要编写代码以获得upvotes!=)