背景:我们有一个应用程序(用 Python 编写),它从各种来源接收数据,对其进行处理,并将结果存储在结果表中。结果表每次都会被覆盖,因为 结果是根据复杂算法组合来自不同来源的数据。有一个业务需求是能够比较不同日期的结果,因此我们现在将每天的结果存储在历史表中,并带有一个额外的字段tag来标识应用程序的每次运行。
例子:
数据:
id company_name vat_id url
123 Funny Company 123456 funny-company.com
数据历史:
tag id company_name vat_id url
2021-05-23 123 Funny Company 123456 funny-company.com
每次运行的结果变化不大 - 大约 3-5% 的行被更改或添加,因此历史表中有 95% 是重复数据。
问题:请建议一个合适的数据模型,它只允许存储执行的最后一个结果,并且有“增量”表,可以让您轻松有效地
为应用程序的任何一天重新创建结果,并且不会占用太多空间?
UPD:在与受人尊敬的评论中交谈之后0xdb,asanisimov现在我倾向于选择以以下格式保存每天的增量:
在右侧,特定日期的恢复数据。现在我试图从左侧显示的数据中了解如何有效地实现这一点?

我使用问题中描述的方式存储版本(尽管在 postgres 中)并进行了一些修改。
有两个表
data_head和data_history。通过继承,它们组合成data_all,我不知道oracle中是否有类似物,可能,您可以使用类似的东西,create view as select * from data_head union all select * from data_history好吧,或者union在请求中明确使用这个。具有特定类型的请求,即 使用视图、显式联合全部或 CTE 对代表性数据进行实验。这些表具有以下结构:
id- 仅在 中唯一data_head,这是实体本身的标识符。snapshot_id它是唯一的版本标识符。serial_number- 版本号。随着每一次变化而增加。modified_date- 版本的创建日期(类似于tag)。我每天有不止一次的变化。在某个时间点获取数据的请求如下所示:
当数据改变时,记录的副本
data_head被插入到data_history中,并且data_head- 被更新。我不知道如何在 Oracle 中实现所有这些,但我必须在 MySQL 中做一个类似的系统。结果出现了以下情况。
只有一张表用于存储数据——包括实际数据和历史数据。诚然,数据可变性更高,达到每月 40-50% 的水平,并且通常的每月分区足以确保足够的性能。
该方案如下:
插入记录时,触发器会检查是否存在与重要字段值相同的记录 和
CURRENT_DATE < valid_till。在没有(新记录)的情况下,该记录被简单地插入。
如果可用,则更新现有记录
SET valid_till = CURRENT_DATE - INTERVAL 1 DAY,插入新记录。没错,我坚持使用两个请求而不是一个请求和一个触发器,但是同志们希望这样。
然后执行第二个查询,找到表中所有不在更新数组中且匹配的记录
CURRENT_DATE < valid_till,它们也运行SET valid_till = CURRENT_DATE - INTERVAL 1 DAY。因此,要获取某个日期的状态,我们只需获取该日期所在的所有记录
BETWEEN valid_from и valid_till。分区允许您忽略 valid_till 小于给定日期的分区。为了进一步加快这样的查询,我建议将日期转换为天数,构建并使用空间索引——他们认为这不合适。
PS。我不知道这个项目的命运。是的,它不再有趣了。
我以问题中的数据模型为基础,几乎没有任何变化。
data_hist不同的是,冗余数据不保存在历史表的更改中。也就是说,第一个插入总是只进入主表。为了在更改历史查询中考虑没有更改的新条目,它们的创建日期必须以某种方式存储。通常,该表已经有一个带有创建日期的列,例如:
给定日期的数据状态查询是对具有相关表连接(在本例中为两个表的连接)的最佳单个记录的标准搜索。它看起来像这样:
插入“临时阶段”准备的新数据的简化示例:
用样本数据和创建添加。db<>fiddle上的对象。
闪回解决方案。此解决方案不需要创建额外的表,它负责保存和删除更改历史记录。所有更改都将作为 UNDO 记录(或更改向量 oldval=>newval)存储在单独的表空间中,也就是说,以用于事务回滚和一致读取的相同格式存储。
您将需要一个可供应用程序用户访问的附加表空间:
接下来,创建一个存档并指示其中的数据存储时间(例如,6 个月),授予用户对新创建的存档的访问权限:
表格可以选择将更改的数据保存在创建的存档中:
从现在开始,表中所有更改的历史
data可以使用 6 个月,并且可以通过带有AS OF子句的简单查询获得: