如何避免将时间戳字段添加到表中?
我对在许多解决方案中看到的每条记录的两个添加列(timeCreated,timeLastUpdated)有疑问。我的问题:还有更好的选择吗?
场景:我们有一个庞大的数据库(就表而言,不是记录),然后客户来要求我们为80%的表添加"时间戳"。
我相信可以通过使用单独的表(TIMESTAMPS)来实现。除了明显的时间戳列之外,该表还将具有表名和要更新的表的主键。 (我在这里假设我们对大多数表使用int作为主键,但是表名很可能必须是字符串)。
为了描述这一点,假设这个基本场景。我们将有两个表:
付款方式:(我们通常的记录)
时间戳:{当前时间戳} + {TABLE_UPDATED
,id_of_entry_updated
,timestamp_type
}
请注意,在此设计中,我们不需要在本机付款对象中使用这两列"额外"列(顺便说一句,可以通过ORM解决方案使它们通过ORM解决方案),因为我们现在通过" TABLE_UPDATED"和" id_of_entry_updated"建立索引。另外," timestamp_type"会告诉我们该条目是用于插入(例如" 1"),更新(例如" 2")还是我们可能想要添加的其他任何内容,例如"删除"。
我想知道我们如何看待这种设计。我对最佳做法最感兴趣,随着时间的流逝,什么是有效的和可扩展的。引用,链接,博客条目非常受欢迎。我知道至少有一项专利(正在申请中)试图解决此问题,但目前看来细节尚未公开。
干杯,
爱德华多
解决方案
建议的方法的优点是,它使我们可以选择将其他字段添加到TIMESTAMP表中,例如跟踪进行更改的用户。我们还可以跟踪对敏感字段的编辑,例如,谁为该合同重新定价?
将记录更改记录在一个单独的文件中意味着我们可以显示一条记录的多个更改,例如:
mm / dd / yy hh:mm:ss由XXX添加
mm / dd / yy hh:mm:ss栏位价格由XXX更改,
mm / dd / yy hh:mm:ss记录已被XXX删除
缺点之一是将要执行的插入到TIMESTAMPS表中的额外代码,以反映主表中的更改。
我想我更喜欢将时间戳添加到各个表中。在复合键(其中之一是字符串)上加入时间戳表的速度会变慢,如果我们有大量数据,最终将是一个真正的问题。
同样,在很多时候,当我们查看时间戳时,就是在调试应用程序中的问题时,我们将需要数据就在那儿,而不必总是与另一个表联接。
我认为,要获得时间戳记,我们必须执行的额外连接将对性能造成轻微影响,并且会令我们痛苦不堪。除此之外,我认为没有问题。
在进行此操作时,还请记录进行更改的用户。
分离表设计的缺陷(除了其他人强调的连接性能之外)是,它假设每个表都有一个键的标识列。并非总是如此。
如果我们使用的是SQL Server,则新的2008版本将支持它们称为"更改数据捕获"的功能,这应该可以减轻我们正在谈论的许多麻烦。我认为Oracle可能也有类似的东西。
更新:显然,Oracle将其称为与SQL Server相同。或者更确切地说,由于Oracle的实现排在第一位,因此SQL Server将其称为与Oracle相同的东西;)
http://www.oracle.com/technology/oramag/oracle/03-nov/o63tech_bi.html
如果将时间戳记东西设置为不使用触发器,则可以记录任何可以触发触发器的操作(读取?)。也可能有一些锁定优势。
(用一小撮盐就可以了,我不是DBA或者SQL专家)
我使用了一种设计,其中要审核的每个表都有两个表:
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"执行任何操作时,都会创建一个数据库触发器,该触发器将填充" NAME_AUDIT"。这样,我们就可以记录对表进行的每个更改以及更改的时间。该应用程序对此没有真正的了解,因为它是由数据库触发器维护的。
它工作得相当好,不需要对应用程序代码进行任何更改即可实现。
是的,我喜欢这种设计,并在某些系统中使用它。通常,以下形式的一些变体:
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
我们所做的正是我们所做的。这对于对象模型以及以最少的代码向我们的模型添加新图章和不同类型图章的功能非常有用。我们还跟踪进行更改的用户,我们的很多逻辑很大程度上都基于这些标记。烧得很好。
一个缺点是报告和/或者在屏幕上显示很多不同的图章。如果我们按照我们的方式进行操作,则会引起大量的连接。另外,后端的更改也很痛苦。
我们的解决方案是除了我们的"会话"表之外,还要维护一个"事务"表。 UPDATE,INSERT和DELETE指令均通过" Transaction"对象进行管理,并且一旦在数据库上成功执行,这些SQL指令中的每一个都将存储在" Transaction"表中。该"事务"表具有其他字段,例如transactiontType(I代表INSERT,D代表DELETE,U代表UPDATE),transactionDateTime等,以及外键" sessionId",最终告诉我们谁发送了指令。甚至有可能通过一些代码来确定谁在何时何地做(Gus在星期一创建了记录,Tim在星期二更改了单价,Liz在星期四增加了额外折扣,等等)。
此解决方案的优点是:
- 我们可以说出"什么人,什么时候什么",并向用户显示! (我们将需要一些代码来分析SQL语句)
- 如果数据被复制,并且复制失败,则可以通过此表重建数据库
缺点是
- 每月10万条数据更新意味着Tbl_Transaction中有10万条记录
- 最后,此表往往占数据库容量的99%
我们的选择:所有早于90天的记录都会在每天早晨自动删除
菲利普
不要简单地删除超过90天的文件,先将它们移动到单独的数据库中或者将其写入文本文件,做一些保留它们的工作,只需将它们从主生产数据库中移出即可。
如果可以归结为它,通常就是"他的文档获胜最多"的情况!
设计的一个噩梦是,每个插入,更新或者删除操作都必须击中该表。这可能会导致主要的性能和锁定问题。这样概括一个表是一个不好的主意(不仅是为了时间戳)。取出数据也将是一场噩梦。
如果代码在GUI级别上由于添加用户不希望看到的字段而中断,则表示我们错误地将代码编写到GUI中,该GUI应该仅指定所需的最小列数,而从不选择*。