繁体   English   中英

跨 EC Core 上下文同步大型数据库表的最佳方法是什么?

[英]What is the best approach to synchronizing large database tables across EC Core contexts?

我的情景

我有三个仓库数据库(Firebird),编号为123 ,每个共享相同的方案和相同的 DbContext 类。 以下是 Products 表的模型:

public class Product
{
    public string Sku { get; }
    public string Barcode { get; }
    public int Quantity { get; }
}

我还有一个本地“仓库缓存”数据库 (MySQL),出于缓存原因,我想在其中定期下载所有三个仓库的内容。 缓存产品的数据模型类似,只是增加了一个数字表示源仓库索引。 此表应包含所有三个仓库的所有产品信息。 如果一个产品同时出现在仓库13 (相同的 Sku)中,那么我希望在本地 Cache 表中有两个条目,每个条目都有对应的仓库 ID:

public class CachedProduct
{
    public int WarehouseId { get; set; } // Can be either 1, 2 or 3
    public string Sku { get; }
    public string Barcode { get; }
    public int Quantity { get; }
}

这个问题有多种可能的解决方案,但考虑到我的数据集的大小(每个仓库约 20k 个条目),它们似乎都不可行或有效,我希望有人能给我一个更好的解决方案。

问题

如果本地缓存数据库是空的,那很容易。 只需从所有三个仓库下载所有产品,并将它们转储到缓存数据库中。 但是,在随后的同步中,缓存 DB 将不再为空。 在这种情况下,我不想再次添加所有 60k 产品,因为这将极大地浪费存储空间。 相反,我想将传入的数据“更新”到缓存中,这样新产品就会正常插入,但是如果缓存中已经存在产品(匹配SkuWarehouseId ),那么我只想更新相应的记录(例如,自上次同步以来,其中一个仓库中的数量可能已更改)。 这样,没有。 缓存数据库中的记录数总是三个仓库的总和; 永远不会多,永远不会少。

到目前为止我尝试过的事情

贪心法:这可能是最简单的一种。 对于每个仓库中的每个产品,检查缓存表中是否存在匹配记录。 如果是则update ,否则insert 明显的问题是没有办法对其进行批处理/优化,这将导致在每次同步时执行数以万计的selectinsertupdate调用。

:Clearing the Cache:每次同步前清除本地缓存DB,重新下载所有数据。 我对这个问题的看法是,它会在没有可用缓存数据的情况下留下一小段时间,这可能会导致应用程序的其他部分出现问题。

使用 EF-Core“Upsert”库:这似乎是FlexLabs.Upsert库最有前途的库,因为它似乎支持批处理操作。 不幸的是,图书馆似乎坏了,因为我什至无法让他们自己的最小示例正常工作。 无论匹配规则如何,每个“upsert”都会插入一个新行。

完全避免 EF Core:我发现了一个名为Dotmim.Sync的库,它似乎是一个 DB 到 DB 同步库。 这样做的主要问题是仓库正在运行该库似乎不支持的 FirebirdDB。 另外,我不确定是否可以进行数据转换,因为我必须在将行添加到缓存数据库之前添加WarehouseId列。


有没有办法在 EF Core 中尽可能高效地做到这一点?

这里有几个选项。 哪些可行取决于您对缓存的陈旧约束。 缓存必须始终 100% 反映仓库状态,否则它会在一段时间内不同步。

首先,您绝对不应该为此使用 EFCore,除非可能作为客户端库来执行原始 SQL。 EfCore 针对许多小型交易进行了优化。 它不适用于批处理工作负载。

“最佳”选项可能是基于事件的系统。 Firebird 支持向事件监听器发送事件,然后它会根据事件更新缓存。 这里的风险是,如果事件处理失败,您可能会失去同步。 您可以通过使用某种事件总线(Rabbit、Kafka)来降低这种风险,但 Firebird 事件处理本身就是薄弱环节。

如果缓存可以处理某些不一致,您可以将到期时间戳附加到每个缓存条目。 您的应用程序会命中缓存,如果过期日期已过,它会重新检查仓库 dbs。 根据更新真实数据库源的业务流程,您可能还可以破坏缓存条目(例如,如果有一个订单管理系统,它可以在有人下订单时破坏订单项的缓存)。

如果您必须批量同步,请执行交换表。 设置一个包含实时缓存数据的表,一个加载新缓存数据的单独表,以及应用程序中的一个标志,说明你从哪个读取。 您在加载到 B 时从表 A 中读取,然后在加载完成后,您切换到从表 B 中读取。

现在,我最终选择了一个完全在 EF Core 中的简单而有效的解决方案。

对于每个缓存条目,我还维护一个 SyncIndex 列。 在同步期间,我从所有三个仓库下载所有产品,将SyncIndex设置为max(cache.SyncIndex) + 1 ,并将它们转储到缓存数据库中。 然后我使用旧的SyncIndex从缓存中删除所有条目。 这样我总是有一些可用的缓存数据,我不会浪费很多空间,而且速度也可以接受。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM