我遇到一个问题,其中有一段如下代码:
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
表包含1亿多条记录...
如您所见,我正在尝试删除所有早于30天的记录...但是,由于我不断出现如下所示的超时情况,因此该操作无效:
执行超时已过期。逾时时间已过 操作完成或服务器没有响应。
对列TransactionDate
进行了索引,它是一个非唯一且非聚集的索引,但这似乎无济于事...我用来执行批量删除的库就是这个:
https://github.com/MikaelEliasson/EntityFramework.Utilities
有人知道更有效的解决方案,或者我怎么解决这个问题?
答案 0 :(得分:1)
您可以尝试增加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 :(得分:1)
我会做些事情来减轻这个问题;
1)实体框架往往要求在允许您删除记录/对象之前先将它们加载到内存中,这本身可能会对性能造成重大影响。
最好为此操作运行一些自定义SQL
2)在数据库表中为字段交易日期创建索引
想象一下,在大型表中运行一个select-> where查询必须执行的操作,给定足够大的记录集,它必须扫描所有这些记录以确定您需要哪些记录。向该表添加索引有助于为数据库提供您最查询的字段线索,并使数据库为您优化这些操作。
3)运行查询超过30天
假设这是一项常规的内部整理操作,那么运行30天以上将使数据库表中的行数保持最少。在某些数据库中,您甚至可以添加时间表,因此无需在代码中包括它。
4)批量删除记录
如果必须为此使用Entity Framework,则可以选择要删除的行(数量为X);这可以帮助分散数据库上的负载,以防万一该操作可能需要花费几分钟的时间来执行。
答案 2 :(得分:1)
我认为索引不是解决方案,而可能是问题所在。 如果表在几列上都有索引,则删除操作可能会锁定记录以更新索引。这是昂贵的,并且花费时间尝试将其分解。获取记录的ID列表,然后将其删除,例如说10,000
答案 3 :(得分:0)
由于删除5万行可能要花费2秒钟以上的时间,因此请以较小的块为单位进行删除;说1000。
此外,请勿“每2秒执行一次”;而是“持续进行”。也就是说,在完成一批之后,再进行下一批。 (可选)在批次之间短暂暂停。按固定的时间表执行删除操作可能会导致绊倒多个同时运行的副本。
这里讨论了几种技术:http://mysql.rjweb.org/doc.php/deletebig
请注意,该链接建议PARTITION BY RANGE(TO_DAYS())
是进行大型删除的最佳方法。建议每天(或每周)进行分区。
答案 4 :(得分:0)
DbContext.Database.CommandTimeout = 0; // set unlimited timeout
或在配置文件中将其设置为0