C# 对 50000 条及更多记录执行批量删除

C# perform bulk delete on 50000 and more records

我有一个问题,我有一段代码如下:

  var inPast = DateTime.Today.AddDays(-30);
    DBRetry.Do(() => EFBatchOperation.For(ctx, ctx.Transactions).Where(t =>  t.TransactionDate <= inPast).Delete(), TimeSpan.FromSeconds(2));

如果发生超时或死锁,DBRetry 函数只是每 2 秒重复一次操作...

现在的问题是我的 Transactions table 包含超过 1 亿条记录...

如您所见,我正在尝试删除所有超过 30 天的记录...但是这不起作用,因为我经常遇到超时,如下所示:

Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

TransactionDate 已编入索引,它是一个非唯一且非聚集索引,但这似乎没有帮助...我用来执行批量删除的库是这个:

https://github.com/MikaelEliasson/EntityFramework.Utilities

有谁知道更有效的解决方案或我如何解决这个问题?

您可以尝试增加 Db 上下文的命令超时:

(最初在 MSDN

public class YourContext : DbContext
{
  public YourContext()
    : base("YourConnectionString")
 {
    // Get the ObjectContext related to this DbContext
    var objectContext = (this as IObjectContextAdapter).ObjectContext;

    // Sets the command timeout for all the commands
    objectContext.CommandTimeout = 120;
  }
}

我会做一些事情来缓解这个问题;

1) Entity Framework 往往要求先将 records/objects 加载到内存中,然后再允许您删除它们,这本身就是一个很大的性能损失。

对于此操作,运行 一些自定义 SQL 可能会更好

2) 在数据库中为字段交易日期table创建索引

想象一下数据库在 table 到 运行 一个 select->where 查询中必须做什么,给定一个足够大的记录集,它必须扫描所有他们来确定您需要哪些记录。向此添加索引 table 有助于为数据库提供您查询最多的字段的线索,并让数据库为您优化这些操作。

3) 运行 查询频率超过 30 天

假设这是一个常规的内务管理操作,运行将其设置的频率超过 30 天将使数据库中的行数 table 保持在最低限度。在某些数据库中,您甚至可以添加计划,因此无需在代码中包含它。

4) 批量删除记录

如果你必须为此使用Entity Framework,你可以select你想删除的行,批量为X;这有助于分配数据库上的负载,以防操作可能需要很长时间才能执行。

我认为索引不是解决方案,可能是问题所在。 如果 table 在多个列上有索引,则删除可能会锁定记录以更新索引。这是昂贵的,并且需要时间尝试将其分解。获取记录的 ID 列表,然后分批删除它们,比如 10,000

由于删除 50K 行可能需要超过 2 秒的时间,因此请分小块进行;说 1000。

还有,不要"do it every 2 seconds";相反 "do it continually"。也就是说,完成一批后,再做下一批。可选择在批次之间短暂暂停。按固定时间表执行删除操作可能会导致同时遇到多个副本 运行。

这里讨论了几种技术:http://mysql.rjweb.org/doc.php/deletebig

请注意,link 建议 PARTITION BY RANGE(TO_DAYS()) 作为执行大删除的最佳方式。建议每日(或每周)分区。

DbContext.Database.CommandTimeout = 0; // set unlimited timeout

或者在配置文件中设置为0

https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.commandtimeout?view=netframework-4.7.2