14

我对我们在许多解决方案中看到的每条记录的两个附加列(timeCreated、timeLastUpdated)有疑问。我的问题:有更好的选择吗?

场景:您有一个巨大的数据库(就表而言,而不是记录而言),然后客户来要求您为 80% 的表添加“时间戳”。

我相信这可以通过使用单独的表(TIMESTAMPS)来完成。除了明显的时间戳列之外,该表还具有正在更新的表的表名和主键。(我在这里假设您使用 int 作为大多数表的主键,但表名很可能必须是字符串)。

为了描绘这个假设这个基本场景。我们将有两个表:

付款:-(您通常的记录)
TIMESTAMP:- {当前时间戳} + { TABLE_UPDATED, id_of_entry_updated, timestamp_type}

请注意,在此设计中,您不需要本机支付对象中的这两个“额外”列(顺便说一下,这可能会通过您的 ORM 解决方案实现),因为您现在正在通过TABLE_UPDATEDand进行索引id_of_entry_updated。此外,timestamp_type它会告诉您条目是否用于插入(例如“1”)、更新(例如“2”)以及您可能想要添加的任何其他内容,例如“删除”。

我想知道你对这个设计有什么看法。我对最佳实践最感兴趣,什么随着时间的推移有效和扩展。参考、链接、博客条目非常受欢迎。我知道至少有一项专利(待批)试图解决这个问题,但目前似乎细节尚未公开。

干杯,爱德华多

4

11 回答 11

12

当您使用它时,还要记录进行更改的用户。

分离表设计的缺陷(除了其他人强调的连接性能)是它假设每个表都有一个标识列作为键。这并不总是正确的。

如果您使用 SQL Server,新的 2008 版本支持他们称之为的东西,Change Data Capture这应该可以消除您所说的很多痛苦。我认为甲骨文可能也有类似的东西。


更新:显然 Oracle 将其称为与 SQL Server 相同的东西。或者更确切地说,SQL Server 将其称为与 Oracle 相同的东西,因为 Oracle 的实现首先出现;)
http://www.oracle.com/technology/oramag/oracle/03-nov/o63tech_bi.html

于 2008-09-30T20:41:50.523 回答
10

我使用了一种设计,每个要审计的表都有两个表:

create table NAME (
  name_id int,
  first_name varchar
  last_name varchar
  -- any other table/column constraints
)

create table NAME_AUDIT (
  name_audit_id int
  name_id int
  first_name varchar
  last_name varchar
  update_type char(1) -- 'U', 'D', 'C'
  update_date datetime
  -- no table constraints really, outside of name_audit_id as PK
)

NAME_AUDIT每次执行任何操作时都会创建一个数据库触发器来填充NAME。这样,您就可以记录对表所做的每一次更改以及何时更改。应用程序对此没有真正的了解,因为它是由数据库触发器维护的。

它工作得相当好,并且不需要对应用程序代码进行任何更改即可实现。

于 2008-09-30T20:45:02.450 回答
5

我想我更喜欢将时间戳添加到各个表中。在复合键上加入时间戳表(其中一个是字符串)会更慢,如果您有大量数据,最终将成为一个真正的问题。

此外,很多时候,当您查看时间戳时,是在您调试应用程序中的问题时,您会希望数据就在此处,而不是总是必须连接到另一个表。

于 2008-09-30T20:41:39.087 回答
2

您的设计的一个噩梦是每次插入、更新或删除都必须命中该表。这可能会导致主要的性能和锁定问题。概括这样的表(不仅仅是时间戳)是一个坏主意。从中获取数据也将是一场噩梦。

如果您的代码会因添加您不希望用户看到的字段而在 GUI 级别中断,则您错误地将代码写入您的 GUI,它应该只指定您需要的最小列数,并且永远不要选择 *.

于 2009-01-27T22:32:50.687 回答
1

您建议的方法的优点是它使您可以选择将其他字段添加到您的 TIMESTAMP 表中,例如跟踪进行更改的用户。您还可以跟踪对敏感字段的编辑,例如谁为该合同重新定价?

在单独的文件中记录记录更改意味着您可以显示对记录的多项更改,例如:

mm/dd/yy hh:mm:ss 由 XXX 添加 mm/dd/yy hh:mm:ss 字段 PRICE 由 XXX 更改,mm/dd/yy hh:mm:ss 记录由 XXX 删除

一个缺点是将执行插入到您的 TIMESTAMPS 表中以反映主表中的更改的额外代码。

于 2008-09-30T20:40:29.420 回答
1

如果您设置时间戳的东西来运行触发器,那么可以记录任何可以触发触发器(读取?)的操作。也可能有一些锁定优势。

(对所有这些都持保留态度,我不是 DBA 或 SQL 大师)

于 2008-09-30T20:43:28.677 回答
1

是的,我喜欢这种设计,并将其与某些系统一起使用。通常,一些变体:

LogID  int
Action varchar(1)     -- ADDED (A)/UPDATED (U)/DELETED (D)
UserID varchar(20)    -- UserID of culprit :)
Timestamp datetime    -- Date/Time
TableName varchar(50) -- Table Name or Stored Procedure ran
UniqueID int          -- Unique ID of record acted upon
Notes varchar(1000)   -- Other notes Stored Procedure or Application may provide
于 2008-09-30T20:45:13.073 回答
0

我认为您必须执行的额外连接才能获得时间戳,这将是轻微的性能损失和颈部疼痛。除此之外,我认为没有问题。

于 2008-09-30T20:41:45.843 回答
0

我们做了你所做的。它非常适合对象模型,并且能够以最少的代码向我们的模型添加新的图章和不同类型的图章。我们也在跟踪做出改变的用户,我们的很多逻辑都很大程度上基于这些标记。它醒得很好。

一个缺点是报告和/或在屏幕上显示许多不同的标记。如果您按照我们的方式进行操作,则会导致很多连接。此外,后端更改是一种痛苦。

于 2008-09-30T20:48:29.197 回答
0

除了我们的“会话”表之外,我们的解决方案是维护一个“事务”表。UPDATE、INSERT 和 DELETE 指令都通过“事务”对象进行管理,一旦在数据库上成功执行,这些 SQL 指令中的每一个都将存储在“事务”表中。这个“Transaction”表还有transactiontType(I代表INSERT,D代表DELETE,U代表UPDATE)、transactionDateTime等字段,还有一个外键“sessionId”,最后告诉我们是谁发出了指令。甚至可以通过一些代码来确定谁在何时做了什么(Gus 在星期一创建了记录,Tim 在星期二更改了单价,Liz 在星期四添加了额外的折扣,等等)。

此解决方案的优点是:

  1. 您可以说出“谁和什么时候”,并将其展示给您的用户!(您需要一些代码来分析 SQL 语句)
  2. 如果你的数据被复制了,并且复制失败了,你可以通过这个表重建你的数据库

缺点是

  1. 每月 100 000 次数据更新意味着 Tbl_Transaction 中有 100 000 条记录
  2. 最后,该表往往占数据库容量的 99%

我们的选择:每天早上自动删除所有超过90天的记录

于 2008-10-02T20:42:28.587 回答
-1

菲利普,

不要简单地删除那些超过 90 天的,首先将它们移动到单独的数据库或将它们写入文本文件,做一些事情来保存它们,只需将它们移出主生产数据库。

如果归根结底,通常是“拥有最多文档的人获胜”!

于 2008-12-09T18:44:30.917 回答