将增量存储在数据库中而不是整个对象中
Posted
技术标签:
【中文标题】将增量存储在数据库中而不是整个对象中【英文标题】:Storing deltas in the database instead of the whole object 【发布时间】:2016-09-13 11:17:02 【问题描述】:我想在数据库中存储/更新具有一长串字段的对象。我打算使用 SQL Server(不是 2016 年)并且我没有预定义的数据格式来存储这个对象,这意味着我可以将它存储在 JSON/BSON 中,作为二进制 blob 等。
但是,对于每次更新,我都希望保留更改的部分,而不是将对象作为一个整体进行存储。对于每个请求,只有其中一些项目会被更改,并且类似于事件溯源,我想重新应用所有这些更改以获得对象的最终版本。我在下面列出了一些限制:
除了更新现有字段的值外,对象将来可能会发生变化。可以添加新字段,甚至可以删除现有字段。我应该能够处理这种情况。当前对象可能与我们上次更新数据库中的项目时的对象完全不同。我看到了Gson,看起来很有趣。 当然应该在性能和节省空间之间取得平衡。但是,节省空间比速度更重要。我阅读了有关 json 补丁和一些针对此类问题的自定义解决方案,但想了解有关此主题的更多信息。但是,我不想重新发明***,但是一种易于实现的方法(如果有库/框架支持当然更好)会很好。
【问题讨论】:
抛开许多其他需要考虑的事情(例如从增量重建对象需要多长时间):请看一下稀疏列和列集的概念msdn.microsoft.com/en-us/library/cc280521.aspx - 也许这个可以帮忙。 我认为您在描述事件溯源 (ES) 和命令查询职责分离 (CQRS)。所以好好学习吧:msdn.microsoft.com/en-us/library/jj591559.aspx @RobertMoskal,你是对的,我在问题中也提到了它(我认为 ES 很好,不需要 CQRS)。但是,我在这里没有具体的活动。我只是得到一个对象的差异,将来可能会发生变化。也许我可以为每个对象定义一个事件,并说事件 X 带有值 Y,表示示例字段“名称”中的更新以将其值设置为“Foo”。但是,这可能会受到对象的不同版本的影响,我必须为每个字段创建一个新事件。可维护性不是很好。 我最近一直在试验这种方法,它很有效。我可以将大型对象网格转换为增量数组,然后将其准确地转换回对象网格。真正的问题是存储所有这些数据是否可行,然后再对其进行再水化,性能是否太差而无法使用。 【参考方案1】:我认为您在描述事件溯源 (ES) 和命令查询职责分离 (CQRS)。所以好好学习吧:https://msdn.microsoft.com/en-us/library/jj591559.aspx
可以用一种小命令语言来描述对 JSON 对象的更改。可以这么简单:
set(property,value)
并将其存储在数据库中。如果你只有一个命令,你完全可以避免存储动词。
您可能希望在属性名称中允许键路径或 .dot 表示法访问嵌套项
set('foo.baz.bar',one:1)
但您可能会觉得需要引入额外的动词来表示设置对象的根或删除键等事件。
重播更改以实现您的实体。阅读性能问题,以便为您的用例提出最佳实施方案。
【讨论】:
如果我们更改了保存在数据库中的对象的布局,并且在更改后数据库中的信息没有更新,该怎么办。 DB中的序列化信息可能与当前对象不兼容。我怎么能理解(版本控制或类似的东西)? 不确定你的意思。您使用命令更改“对象的布局”,该命令将应用于数据库。数据库表示始终是唯一的事实来源。我可以看到客户没有被告知更改,无法操作数据。我很乐意就这个话题聊几分钟。 我计划将一个对象序列化/反序列化到 json。因此,我想存储的对象可能会随时间而变化。例如,我可以添加一个新成员等。但是,我的一条记录可能不包含任何内容(例如:由于该记录不活动,历史记录中没有添加命令)。 json 的模式不再与实际对象相关。 这是这些场景中的普遍问题。当您的客户没有得到他们期望的数据时,他们可以“聪明而宽容”。当您的客户没有得到他们需要的东西时,他们可能会简单地“失败”。您还可以使用补偿事务返回并根据需要转换所有实体。您可以将它们作为批处理运行。您可能会混合使用所有三种技术。 我明白了,版本控制在那种情况下可能会有所帮助吗?但是,为了序列化/反序列化,我还必须保留对象的每个版本。此外,我必须在必要时在它们之间进行转换。以上是关于将增量存储在数据库中而不是整个对象中的主要内容,如果未能解决你的问题,请参考以下文章