与许多数据库一样,我正在设计一个数据库,该数据库应记录每个表中更改的行的先前版本。
此问题的标准解决方案是为每个数据表保留历史记录表, 每当需要在数据表中更新行时,当前行的副本将被插入到历史表中,而不是数据表中的行得到更新。
这个解决方案的缺点对我来说:
我正在考虑一个不同的解决方案,并想知道它是否正常。 对于每个表,我们添加列IS_LAST
假设在我的情况下,行平均更新10次。 还假设应用程序执行的操作中至少有90%仅在最新版本的行上发生。
我的数据库是一个Oracle 10g,所以为了使“活动”表保持苗条,我们可以将表拆分为2个分区:IS_LAST = 1分区和IS_LAST = 0分区。
分区是解决历史数据保持问题的好方法吗?
此解决方案是否会限制这些表的其他分区潜力?
谢谢!
答案 0 :(得分:6)
第一个问题应该是:你会对这些数据做些什么?如果您没有明确的业务要求,请不要这样做。
我做了类似的事情,经过3年的运行,大约有20%的“有效数据”,其余的是“以前的版本”。它有1000万+ 4000万条记录。在过去三年中,我们有两(2)次调查变更历史的请求,两次请求都是愚蠢的 - 我们记录了记录变更的时间戳,我们被要求检查人员是否加班(下午5点之后)。
现在,我们陷入了超大型数据库,其中包含80%无人需要的数据。
修改强>
既然你问过可能的解决方案,我会描述我们做了什么。它与您正在考虑的解决方案略有不同。
我们使用以下列记录单个存档表中的所有更改:
事情就是这样:
临:
缺点:
LIKE
运算符。所以,再次,检查存档上的要求。这不是一项微不足道的任务,但收益和使用可以是最小的。
答案 1 :(得分:2)
我创建了两个表:一个用于IsLast类值,一个用于历史值。然后我会设置一个触发器,每次更新isLast时都会将值插入历史表中。
答案 2 :(得分:1)
如果我有1或2个历史表保留,我会像Tuinstoel建议的那样完成。但如果你有几十个表来做这件事,我会更倾向于zendar描述的解决方案。原因是这样的。
你如何回答像
这样的问题自昨天一切正常以来发生了什么变化?
用户SMITHG是否进行了任何更改?
这些问题需要每个表一个查询,无论是单独的_hist表还是表中的分区。无论如何,这是一些巨大的查询列表。如果你有一个看起来像这样的中央表,那么它就是一块馅饼。
table_name, Column_name, PK, Before_value, After_value, User, timestamp
插入仅在值之后
删除仅在值之前,
更新只有改变的列。
一些变化
如果您愿意,可以为I / U / D添加一列 您可以排除插入的列值,只记录PK和I,因为正确的值仍在表中。
由于这是Oracle,你可以在table_name上进行分区,所以实际上你实际上每个真实表都有一个hist“table”。
您可以轻松回答上述问题,我相信这些问题非常简单,是最常见的问题。它可以处理您可以使用分区或_hist表回答的每个问题。
答案 3 :(得分:1)
由于您使用的是Oracle,因此可以查看Oracle Flashback Technology。它记录数据库中所有更改的更改,包括数据和结构。它还记录时间戳和用户名。
我没有使用它,但它看起来很有能力。
答案 4 :(得分:0)
我想到的主要限制是,您的表的很大一部分将是历史数据,这意味着索引问题并可能在CRUD查询中引入额外的复杂性。
是否有一些特殊原因你不想使用通常解决这种情况的方法?
答案 5 :(得分:0)
您将如何定义主键?由于在同一个表中连接历史记录行,因此将有许多行具有相同的主键。
当单个“真实”行更改一次时,您似乎无法知道历史记录行的顺序。
(我参与过的一个项目,我们使用codesmith生成了所有历史表和触发器,这非常有用。)
答案 6 :(得分:0)
我会使用IS_LAST=1
分区和IS_LAST=0
分区系统。因为它是分区的,所以它会很快(分区修剪),你将永远不必查询普通表和历史表的并集。
我会使用IS_LAST ='Y'/'N'而不是1/0。 1和0毫无意义。
有一个特殊的技巧可以帮助保证每个实体最多有一行IS_LAST='Y'
:您可以创建一个基于函数的唯一索引,其函数在IS_LAST='N'
时返回null并返回IS_LAST='Y'
时的ID这里解释:http://www.akadia.com/services/ora_function_based_index_1.html
答案 7 :(得分:0)
根据时间跟踪它会帮助您在日常工作结束时或在工作结束时或在工作结束时或在工作结束时获得效果,具体取决于执行将尾随数据移入的过程的最低交易量时间那么历史表会有帮助吗?这样你所有的更新都将是插入,也不需要锁定。此致,安迪
答案 8 :(得分:0)
这完全取决于你拥有的东西:
答案 9 :(得分:0)
与其他人一样,我使用ORM(Propel)和一个包含自定义保存的基础对象。删除方法。这些方法优先于标准保存和放大。删除ORM附带的内容。他们检查哪些列已更改,并在更改表中为每个更改的列创建1行。
change
表的架构:
change_pk,user_fk,user_name,session_id,ip_address,method,table_name,row_fk,field_name,field_value,most_recent,date_time
实施例: 1,4232,'Gnarls Barkley','f2ff3f8822ff23','234.432.324.694','更新','用户',4232,'first_name','Gnarles','Y','2009-08-20 10:10 :10' ;