[英]EF Core Bulk Delete on PostgreSQL
我正在嘗試對單個表執行潛在的大規模刪除操作。 (想想 1m 行表上的 100,000 行)
我正在使用 PostgreSQL 和 EntityFrameworkCore。
詳細信息:應用程序代碼有一個要匹配的謂詞,並且不知道有多少行可能與該謂詞匹配。 它可能是 0 row/s 或非常大的數量。
研究表明 EF Core 無法有效處理此問題。 (即以下代碼為每一行生成一個 Delete 語句!)
Using (var db = new DbContext)
var queryable = db.Table.AsQueryable()
.Where(o => o.ForeignKey == fKey)
.Where(o => o.OtherColumn == false);
db.Table.RemoveRange(queryable);
await db.SaveChangesAsync();
所以這是我更喜歡在批處理操作中運行的 SQL:
delete from Table
where ForeignKey = 1234
and OtherColumn = false
and PK in (
select PK
from Table
where ForeignKey = 1234
and OtherColumn = false
limit 500
)
那里有擴展庫,但我還沒有找到一個支持 Postgres 的活躍庫。 我目前正在通過 EF Core 執行上面的原始 sql。
這導致了幾個問題:
免責聲明:我是Entity Framework Plus項目的所有者
您的場景看起來是我們的Batch Delete
功能可以處理的: https : //entityframework-plus.net/batch-delete
Using (var db = new DbContext)
var queryable = db.Table.AsQueryable()
.Where(o => o.ForeignKey == fKey)
.Where(o => o.OtherColumn == false);
queryable.Delete();
實體未加載到應用程序中,僅按您指定的方式執行 SQL。
我認為您正在嘗試做一些不應該使用 EntityFrameworkCore 的事情。 EntityFrameworkCore 的目標是提供一種在 .Net-Core 應用程序和數據庫之間移動數據的好方法。 典型的使用方式是單個或少量對象。 對於批量操作,有一些 nuget 包。 有這個用於插入和更新 postgres 的包。 作者的這篇文章解釋了它如何使用臨時表和 postgres COPY 命令進行批量操作。 這向我們展示了一種通過 id 批量刪除行的方法:
var toDelete = GetIdsToDelete();
using (var conn = new NpgsqlConnection(connectionString))
{
conn.Open();
using ( var cmd = conn.CreateCommand())
{
cmd.CommandText =("CREATE TEMP TABLE temp_ids_to_delete (id int NOT NULL) ON COMMIT DROP ");
cmd.Prepare();
cmd.ExecuteNonQuery();
}
using (var writer = conn.BeginBinaryImport($"COPY temp_ids_to_delete (id) FROM STDIN (FORMAT BINARY)"))
{
foreach (var id in toDelete)
{
writer .StartRow();
writer .Write(id);
}
writer .Complete();
}
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "delete from myTable where id in(select id from temp_ids_to_delete)";
cmd.Prepare();
cmd.ExecuteNonQuery();
}
conn.Close();
通過一些小的變化,這可以更普遍。
但是你想做一些不同的事情。 您不想在應用程序和數據庫之間移動數據或信息。 您想使用 efcore 動態創建 slq 過程並在服務器上運行該過程。 問題是 ef 核心並不是真正的構建來做到這一點。 但也許有辦法解決這個問題。 我能想到的一種方法是使用 ef-core 構建查詢,獲取查詢字符串,然后將該字符串插入另一個 sql-string 以在服務器上運行。 獲取查詢字符串目前並不容易,但顯然它會與 EF Core 5.0 一起使用。 那么你可以這樣做:
var queryable = db.Table.AsQueryable()
.Where(o => o.ForeignKey == fKey)
.Where(o => o.OtherColumn == false);
var queryString=queryable.ToQueryString();
db.Database.ExecuteSqlRaw("delete from Table where PK in("+queryString+")" )
是的,這是非常hacky,我不推薦。 我建議在 databaseServer 上編寫過程和函數,因為這不是 ef-core 應該使用的。 然后你仍然可以從 ef-core 運行這些函數並傳遞參數。
我建議使用臨時表來執行這樣的操作。 您將創建一個鏡像臨時表,將要保留或刪除的記錄批量添加到臨時表中,然后執行刪除操作以在該臨時表中/不在該臨時表中查找記錄。 嘗試使用諸如 PgPartner 之類的庫來輕松完成批量添加和臨時表創建。
查看 PgPartner: https ://www.nuget.org/packages/PgPartner/
這可以通過BulkExtensions完成
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.