[英]What is the best approach to synchronizing large database tables across EC Core contexts?
我有三個倉庫數據庫(Firebird),編號為1
、 2
和3
,每個共享相同的方案和相同的 DbContext 類。 以下是 Products 表的模型:
public class Product
{
public string Sku { get; }
public string Barcode { get; }
public int Quantity { get; }
}
我還有一個本地“倉庫緩存”數據庫 (MySQL),出於緩存原因,我想在其中定期下載所有三個倉庫的內容。 緩存產品的數據模型類似,只是增加了一個數字表示源倉庫索引。 此表應包含所有三個倉庫的所有產品信息。 如果一個產品同時出現在倉庫1
和3
(相同的 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 產品,因為這將極大地浪費存儲空間。 相反,我想將傳入的數據“更新”到緩存中,這樣新產品就會正常插入,但是如果緩存中已經存在產品(匹配Sku
和WarehouseId
),那么我只想更新相應的記錄(例如,自上次同步以來,其中一個倉庫中的數量可能已更改)。 這樣,沒有。 緩存數據庫中的記錄數總是三個倉庫的總和; 永遠不會多,永遠不會少。
貪心法:這可能是最簡單的一種。 對於每個倉庫中的每個產品,檢查緩存表中是否存在匹配記錄。 如果是則update
,否則insert
。 明顯的問題是沒有辦法對其進行批處理/優化,這將導致在每次同步時執行數以萬計的select
、 insert
和update
調用。
: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.