Bulkdelete 高效,稳定删除上亿条数据。

打印 上一主题 下一主题

主题 1833|帖子 1833|积分 5499

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
以下是一个基于 Entity Framework Extensions 的 BulkDelete 高效删除海量数据的方案,包含性能优化、稳定性保障和错误处理机制:
csharp
using System;
using System.Linq;
using Z.EntityFramework.Plus;
public class BulkDeleteService
{
private const int BatchSize = 50000; // 根据服务器内存和网络调解
private const int MaxRetryAttempts = 3;
private readonly TimeSpan RetryDelay = TimeSpan.FromSeconds(5);
  1. public void BulkDeleteRecords(MyDbContext context, DateTime deleteBefore)
  2. {
  3.     var query = context.YourEntities
  4.         .Where(x => x.CreatedDate < deleteBefore)
  5.         .OrderBy(x => x.Id); // 按主键排序确保分页稳定
  6.     int totalDeleted = 0;
  7.     bool hasMoreData = true;
  8.    
  9.     var deleteOptions = new BulkDeleteOptions
  10.     {
  11.         BatchSize = BatchSize,
  12.         UseTransaction = false, // 关闭事务提升性能
  13.         CommandTimeout = 600,    // 适当延长超时时间
  14.         ExecuteHook = (x) =>
  15.         {
  16.             // 内存优化配置
  17.             x.BatchTimeout = 60;
  18.             x.TrackingEntities = false;
  19.         }
  20.     };
  21.     while (hasMoreData)
  22.     {
  23.         try
  24.         {
  25.             // 分页删除(使用子查询确保分页准确)
  26.             var subQuery = query.Take(BatchSize);
  27.             int deletedCount = RetryPolicy(() => subQuery.DeleteFromQuery(deleteOptions));
  28.             totalDeleted += deletedCount;
  29.             hasMoreData = deletedCount == BatchSize;
  30.             Console.WriteLine($"Deleted {totalDeleted:N0} records, LastID: {GetLastProcessedId(context)}");
  31.             
  32.             // 定期释放资源
  33.             if (totalDeleted % (BatchSize * 10) == 0)
  34.             {
  35.                 context.Dispose();
  36.                 context = new MyDbContext();
  37.                 query = context.YourEntities.Where(...); // 重建查询
  38.             }
  39.         }
  40.         catch (Exception ex)
  41.         {
  42.             LogError(ex, totalDeleted);
  43.             throw; // 根据业务需求决定是否终止
  44.         }
  45.     }
  46. }
  47. private int RetryPolicy(Func<int> action)
  48. {
  49.     int attempts = 0;
  50.     while (true)
  51.     {
  52.         try
  53.         {
  54.             return action();
  55.         }
  56.         catch (SqlException ex) when (attempts < MaxRetryAttempts)
  57.         {
  58.             if (IsTransientError(ex.Number))
  59.             {
  60.                 attempts++;
  61.                 Thread.Sleep(RetryDelay);
  62.                 continue;
  63.             }
  64.             throw;
  65.         }
  66.     }
  67. }
  68. private bool IsTransientError(int errorNumber)
  69. {
  70.     // SQL Server 瞬态错误代码列表
  71.     int transientErrors = { 4060, 40197, 40501, 40613, 49918, 49919, 49920, 4221 };
  72.     return transientErrors.Contains(errorNumber);
  73. }
  74. private long GetLastProcessedId(MyDbContext context)
  75. {
  76.     return context.YourEntities
  77.         .OrderByDescending(x => x.Id)
  78.         .Select(x => x.Id)
  79.         .FirstOrDefault();
  80. }
  81. private void LogError(Exception ex, int processedCount)
  82. {
  83.     // 记录错误和当前进度到持久化存储
  84.     File.AppendAllText("delete_log.txt",
  85.         $"{DateTime.UtcNow:u} Error after {processedCount} records: {ex}\n");
  86. }
复制代码
}
关键优化点:

  • 分页计谋优化:


  • 使用 Take(BatchSize).DeleteFromQuery() 确保准确分页
  • 按主键排序制止数据重复或遗漏
  • 通过子查询实现稳定分页

  • 性能加强:


  • 禁用实体跟踪 (TrackingEntities = false)
  • 批量提交而非事务包裹整个操作
  • 定期重建 DbContext 释放内存
  • 调解批量大小(建议5万-10万/批)

  • 稳定性保障:


  • 瞬态错误重试机制(支持SQL超时、毗连中断等)
  • 进度记录到文件(支持断点续删)
  • 独立的错误日记记录
  • 内存走漏预防(定期释放上下文)

  • 数据库优化建议:
    sql
    -- 实行前建议操作
    ALTER DATABASE YourDB SET RECOVERY SIMPLE;
    EXEC sp_configure 'max server memory', '4096'; -- 根据服务器调解
    ALTER DATABASE YourDB SET DELAYED_DURABILITY = FORCED;
-- 实行后建议
UPDATE STATISTICS YourTable WITH FULLSCAN;
ALTER INDEX ALL ON YourTable REBUILD;

  • 实行计谋:


  • 建议在低峰时段实行
  • 提前备份目的数据
  • 使用数据库镜像/AlwaysOn在从库实行
  • 监控锁状态(sp_who2, sys.dm_tran_locks)
<ol start="6">高级方案:
csharp
// 分区并行删除(需要物理分区)
Parallel.ForEach(GetPartitionRanges(), range =>
{
using var ctx = new MyDbContext();
ctx.YourEntities
.Where(x => x.Id > range.Start && x.Id  x.CreatedDate >= range.Start && x.CreatedDate < range.End)
.DeleteFromQuery();
}</p>注意事项:

  • 建议先在测试情况验证删除逻辑
  • 确保删除条件字段有符合的索引(CreatedDate或ID)
  • 监控事务日记增长(特别是FULL恢复模式)
  • 思量使用Table Partitioning处理持续的大数据删除
对于超大规模数据(超过1亿条),建议结合数据库原生工具(如SQL Server的Partition Switching)实现秒级数据删除。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天津储鑫盛钢材现货供应商

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表