如何避免向表中添加时间戳字段? [关闭]
Posted
技术标签:
【中文标题】如何避免向表中添加时间戳字段? [关闭]【英文标题】:How do you avoid adding timestamp fields to your tables? [closed] 【发布时间】:2010-09-14 08:58:44 【问题描述】:我有一个关于我们在许多解决方案中看到的每条记录的两个附加列(timeCreated、timeLastUpdated)的问题。我的问题:有更好的选择吗?
场景:您有一个巨大的数据库(就表而言,而不是记录而言),然后客户来要求您为 80% 的表添加“时间戳”。
我相信这可以通过使用单独的表 (TIMESTAMPS) 来完成。除了明显的时间戳列之外,该表还具有正在更新的表的表名和主键。 (我在这里假设您使用 int 作为大多数表的主键,但表名很可能必须是字符串)。
假设这个基本场景。我们将有两个表:
付款:-(您通常的记录)
TIMESTAMP :- 当前时间戳 + TABLE_UPDATED
, id_of_entry_updated
, timestamp_type
请注意,在此设计中,您不需要本地支付对象中的这两个“额外”列(顺便说一下,这可能会通过您的 ORM 解决方案实现),因为您现在按 TABLE_UPDATED
和 @ 进行索引987654325@。此外,timestamp_type
会告诉您该条目是否用于插入(例如“1”)、更新(例如“2”)以及您可能想要添加的任何其他内容,例如“删除”。
我想知道您对此设计有何看法。我对最佳实践最感兴趣,什么是随着时间的推移有效和扩展的。参考、链接、博客条目非常受欢迎。我知道至少有一项专利(正在申请中)试图解决这个问题,但目前似乎没有公开细节。
干杯, 爱德华多
【问题讨论】:
【参考方案1】:您的设计的一个噩梦是每次插入、更新或删除都必须命中该表。这可能会导致主要的性能和锁定问题。概括这样的表(不仅仅是时间戳)是一个坏主意。从中获取数据也将是一场噩梦。
如果您的代码会因添加您不希望用户看到的字段而在 GUI 级别中断,那么您将代码错误地写入您的 GUI,它应该只指定您需要的最小列数,并且永远不要选择 *.
【讨论】:
【参考方案2】:在您进行此操作时,还要记录进行更改的用户。
分离表设计的缺陷(除了其他人强调的连接性能)是它假设每个表都有一个标识列作为键。这并不总是正确的。
如果您使用 SQL Server,新的 2008 版本支持他们称之为 @987654321@
的东西,这应该可以消除您所说的很多痛苦。我认为 Oracle 可能也有类似的东西。
更新:显然,Oracle 将其称为与 SQL Server 相同的东西。或者更确切地说,SQL Server 将其称为与 Oracle 相同的东西,因为 Oracle 的实现首先出现;)http://www.oracle.com/technology/oramag/oracle/03-nov/o63tech_bi.html
【讨论】:
这是一篇让我最开心的帖子。我正准备写一篇希望正是这个的帖子。我不认为甲骨文有这样的东西。如果是这样,我会踢自己。 想到我一直在浪费时间将 ModifiedBy 和 CreatedDateTime 字段添加到我的表中,我很生气。 嗯,是的,Oracle 已经有这个多年了。 该功能的名称怎么样,感兴趣的人可以找到相关信息?【参考方案3】:菲利普,
不要简单地删除那些超过 90 天的,首先将它们移动到单独的数据库或将它们写入文本文件,做一些事情来保存它们,只需将它们移出主生产数据库。
如果归根结底,通常是“拥有最多文档的人获胜”!
【讨论】:
【参考方案4】:我们的解决方案是在“会话”表之外维护一个“事务”表。 UPDATE、INSERT 和 DELETE 指令都通过“事务”对象进行管理,一旦在数据库上成功执行,这些 SQL 指令中的每一个都将存储在“事务”表中。这个“Transaction”表还有transactiontType(I代表INSERT,D代表DELETE,U代表UPDATE)、transactionDateTime等其他字段,还有一个外键“sessionId”,最后告诉我们是谁发出了指令。甚至可以通过一些代码来确定谁在什么时候做了什么(Gus 在星期一创建了记录,Tim 在星期二更改了单价,Liz 在星期四增加了额外的折扣,等等)。
此解决方案的优点是:
-
您可以说出“谁在什么时候做什么”,并将其展示给您的用户! (您需要一些代码来分析 SQL 语句)
如果您的数据被复制,并且复制失败,您可以通过此表重建您的数据库
缺点是
-
每月 100 000 次数据更新意味着 Tbl_Transaction 中有 100 000 条记录
最后,这个表往往占数据库容量的 99%
我们的选择:每天早上自动删除所有超过 90 天的记录
【讨论】:
【参考方案5】:是的,我喜欢这种设计,并在某些系统中使用它。通常,一些变体:
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
【讨论】:
【参考方案6】:我们完全按照您的做法做了。它非常适合对象模型,并且能够以最少的代码向我们的模型添加新的图章和不同类型的图章。我们也在跟踪做出改变的用户,我们的很多逻辑都很大程度上基于这些标记。它醒得很好。
一个缺点是报告和/或在屏幕上显示许多不同的标记。如果您按照我们的方式进行操作,则会导致很多连接。此外,后端更改也很痛苦。
【讨论】:
【参考方案7】:我使用的设计是每个要审计的表都有两个表:
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
的数据库触发器。这样,您就可以记录对表所做的每一次更改以及何时更改。应用程序对此一无所知,因为它是由数据库触发器维护的。
它工作得相当好,不需要对应用程序代码进行任何更改即可实现。
【讨论】:
+1 这里最大的优势是审计表可以稍后添加,而不会更改它们正在审计的架构;谢谢,我想知道如何为我正在构建的数据库完成此操作!【参考方案8】:如果您将时间戳设置为运行触发器,则可以记录任何可以触发触发器(读取?)的操作。也可能有一些锁定优势。
(持保留态度,我不是 DBA 或 SQL 大师)
【讨论】:
【参考方案9】:我认为您必须执行的额外连接才能获得时间戳,这将是轻微的性能损失和颈部疼痛。除此之外,我认为没有问题。
【讨论】:
【参考方案10】:我想我更喜欢将时间戳添加到各个表中。在复合键(其中一个是字符串)上加入时间戳表会更慢,如果您有大量数据,最终将成为一个真正的问题。
此外,很多时候,当您查看时间戳时,是在您调试应用程序中的问题时,您会希望数据就在那儿,而不是总是必须与另一个表连接。
【讨论】:
连接不需要使用字符串作为“ON”子句的一部分。如果它是索引的第一部分,则每个查询可能只检查一次,具体取决于优化器的性能。 但是如果他将来自不同表的时间戳存储在一个大的 TIMESTAMP 表中,他将需要区分 INVOICE 时间戳和 USERACCOUNT 时间戳,所以它不必是:ON TIMESTAMP.id_of_entry AND 表名 = 'INVOICE'? 我相信你说得有道理,Dana。但是,由于表名是唯一的,您认为我可以使用简单的哈希(例如使用表名的 ascii 表示使其成为 int)吗?这样我最终会在两个 int 字段上建立索引。你怎么看?【参考方案11】:您建议的方法的优点是它使您可以选择将其他字段添加到您的 TIMESTAMP 表中,例如跟踪进行更改的用户。您还可以跟踪对敏感字段的编辑,例如谁为该合同重新定价?
在单独的文件中记录记录更改意味着您可以显示对记录的多项更改,例如:
mm/dd/yy hh:mm:ss 添加者 XXX mm/dd/yy hh:mm:ss 字段 PRICE 由 XXX 更改, mm/dd/yy hh:mm:ss 记录被XXX删除
一个缺点是额外的代码将执行插入到您的 TIMESTAMPS 表中以反映主表中的更改。
【讨论】:
以上是关于如何避免向表中添加时间戳字段? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章