DotNetNext / SqlSugar

.Net aot ORM Fastest ORM Simple Easy VB.NET Sqlite orm Oracle ORM Mysql Orm 虚谷数据库 postgresql ORm SqlServer oRm 达梦 ORM 人大金仓 ORM 神通ORM C# ORM , C# ORM .NET ORM NET5 ORM .NET6 ORM ClickHouse orm QuestDb ,TDengine ORM,OceanBase orm,GaussDB orm ,Tidb orm Object/Relational Mapping
https://www.donet5.com/Home/Doc
MIT License
5.19k stars 1.32k forks source link

是否能評估BulkMerge或BulkUpsert功能? #1193

Closed Yumitoya8569 closed 9 months ago

Yumitoya8569 commented 9 months ago

疑慮

目前批量新增或插入, sugar提供的解決方案是這樣的

Db.Storageable(list).PageSize(1000).ExecuteSqlBulkCopy();

1.對於大表的大型Upsert, 透過Storage需要遍歷當前資料庫, 效能可能不是那麼理想 2.部分資料庫的Bulk操作會放棄對PK約束的檢查, 如果Upsert途中有Storage不知道的新資料從其他系統插入此表, 有低概率導致表不可用

提案

出於以上原因, 不知道是否能評估BulkMerge或BulkUpsert功能? 行為類似BulkUpdate, 把資料BulkCopy塞到一個臨時表再透過Merge或Upsert語句更新主表

Db.Fastest<TableA>(list).ExecuteSqlBulkMerge();
DotNetNext commented 9 months ago

只更新不插入 可以用 db.Fastest().BulkUpdate(GetList())//更新

DotNetNext commented 9 months ago

有这个功能

Yumitoya8569 commented 9 months ago

要插入+更新的 透過Storage來處理有上述疑慮(1.要遍歷資料表, 2.有鍵值重複損壞資料表的風險) 所以才發這個issue討論

Yumitoya8569 commented 9 months ago

另外一個衍生議題 Fastest.BulkCopy這個功能也是沒鍵值檢查的話有損壞資料表的風險 如果要確保BulkCopy的絕對不會有問題, 一樣要在BulkCopy前遍鎖表並遍歷鍵值 BulkCopy結束後才解鎖資料表

是否能評估安全版本? 方案是:

  1. 建立暫存表
  2. BulkCopy到暫存表
  3. 如果沒有事務則開啟局部事務
  4. select into 到主表
  5. 如果局部事務存在則提交與關閉
  6. 刪除暫存表
DotNetNext commented 9 months ago
 db.BeginTran();
  db.Storageable(getAll)
.TranLock()//启用锁
.ExecuteSqlBulkCopy();
 db.CommitTran();
DotNetNext commented 9 months ago

SqlSugarCore 5.1.4.108-preview02 升级到这个版本 对于 PageSize(1000)也支持了锁以前不支持的

DotNetNext commented 9 months ago

db.BeginTran(); //TranLock使用行锁 db.Storageable(new Order() { Id=1, Name="jack" }).TranLock().PageSize(1000).ExecuteSqlBulkCopy();

db.CommitTran();

Yumitoya8569 commented 9 months ago

是這樣的, Oracle不支持BulkCopy事務 再加上鍵值檢查 如有其他程式也正在寫入 撈取的鍵值有可能是舊的 才有了這次的提議

整理一下提議:

  1. Fastest.BulkMerge 支持
  2. Fastest.BulkCopy的Safe模式支持

思路跟BulkUpdate現有的實作是一樣的:

  1. 透過BulkCopy將資料塞入暫存表
  2. 透過Merge或Insert Into select語法將資料塞回主表

提議好處:

  1. 大型資料表(千萬級)插入大資料, 不需將資料撈到程式中確認鍵值是否已存在
  2. 即使BulkCopy不檢查約束也不會導致主表損壞不可用(以Oracle為例, 直接BulkCopy表會導致鍵值重複, 使表不可用)
  3. 對不支持BulkCopy事務的資料庫, 也可以將事務在Merge或Insert Into select的階段處理, BulkCopy放在事務外
  4. 有任何錯誤會先發生在暫存表, 不會對主表產生影響

您再評估看看有沒有納入庫的價值, 謝謝

DotNetNext commented 9 months ago

原来如此,目前还真只有oracle bulkcopy不支持外部事务,研究一下

DotNetNext commented 9 months ago

SqlSugarCore 5.1.4.109-preview02 已支持了

     db.Fastest<UnitaafdsTest>() .BulkMerge(list2);
DotNetNext commented 9 months ago

列新到最新预览版本就行了

DotNetNext commented 9 months ago

至于 Fastest.BulkCopy的Safe 文档有修复方案 或者你直接用

SqlSugarCore 5.1.4.109-preview02 已支持了

db.Fastest<UnitaafdsTest>() .BulkMerge(list2);

DotNetNext commented 9 months ago

还有疑问发新贴