You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core控制台应用优化:50万条JSON数据读写插入提速

50万条JSON数据批量插入优化方案

原代码性能瓶颈分析

  1. 删除操作先全量查询再删除,大量占用内存且执行效率低下
  2. EF上下文长期持有实体追踪,导致内存占用飙升,SaveChanges执行速度随批次增加逐渐变慢
  3. JSON解析多了JObject中间转换步骤,额外消耗CPU资源
  4. 批次大小设置可能未匹配数据库最优处理能力

核心优化措施

  • 批量删除替代查询后删除:用EF Core原生的ExecuteDelete直接执行SQL级删除,无需将实体加载到内存
  • 禁用实体追踪:插入时关闭上下文的自动追踪,减少内存消耗与变更检测开销
  • 优化JSON解析:直接反序列化为目标实体,跳过JObject中间转换
  • 调整批次大小:根据数据库性能调整(推荐2000-5000,需测试确定最优值)
  • 批次独立上下文:每个批次使用全新上下文,避免追踪缓存累积

优化后完整代码

// 批量删除目标数据,直接执行SQL DELETE语句,无需加载实体
using (var context = new ApplicationDbContext())
{
    var deleteCount = context.tblDispense
        .Where(p => p.HfrCode == facilityName)
        .ExecuteDelete(); // EF Core 3.0+支持,性能远优于查询后删除
    Console.WriteLine($"[{facilityName}] 已删除 {deleteCount} 条历史数据");
}

// 流式读取JSON并批量插入
using (StreamReader sr = new StreamReader(filePath))
using (JsonTextReader reader = new JsonTextReader(sr))
{
    var serializer = new JsonSerializer();
    while (reader.Read())
    {
        if (reader.TokenType == JsonToken.StartArray && reader.Path == "tblDispense")
        {
            const int batchSize = 2000; // 可根据数据库性能调整
            List<TblDispense> tblDispenseBatch = new List<TblDispense>(batchSize); // 预分配容量减少内存扩容开销

            while (reader.Read() && reader.TokenType != JsonToken.EndArray)
            {
                if (reader.TokenType == JsonToken.StartObject)
                {
                    // 直接反序列化为实体,跳过JObject中间转换
                    var tblDispense = serializer.Deserialize<TblDispense>(reader);
                    tblDispense.UUID = $"{Guid.NewGuid()}.{facilityName}";
                    tblDispense.MSDCode = $"{tblDispense.MSDCode}.{facilityName}";
                    tblDispense.DispenseID = $"{tblDispense.DispenseID}.{facilityName}";
                    tblDispense.DispenseRecordId = $"{tblDispense.DispenseRecordId}.{facilityName}";
                    tblDispense.HfrCode = facilityName;
                    tblDispenseBatch.Add(tblDispense);

                    if (tblDispenseBatch.Count >= batchSize)
                    {
                        try
                        {
                            using (var context = new ApplicationDbContext())
                            {
                                // 禁用实体追踪,大幅提升插入速度
                                context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
                                context.tblDispense.AddRange(tblDispenseBatch);
                                context.SaveChanges();
                            }
                            tblDispenseBatch.Clear();
                            Console.WriteLine($"[{facilityName}] 已完成 {batchSize} 条数据插入");
                        }
                        catch (DbUpdateException ex)
                        {
                            Console.WriteLine($"[{facilityName}] 批量插入出错: {ex.InnerException?.Message}");
                            logger.LogError(ex, $"[{facilityName}] 批量插入出错");
                        }
                    }
                }
            }

            // 插入剩余未达批次量的数据
            if (tblDispenseBatch.Count > 0)
            {
                try
                {
                    using (var context = new ApplicationDbContext())
                    {
                        context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
                        context.tblDispense.AddRange(tblDispenseBatch);
                        context.SaveChanges();
                    }
                    Console.WriteLine($"[{facilityName}] 已完成剩余 {tblDispenseBatch.Count} 条数据插入");
                }
                catch (DbUpdateException ex)
                {
                    Console.WriteLine($"[{facilityName}] 剩余数据插入出错: {ex.InnerException?.Message}");
                    logger.LogError(ex, $"[{facilityName}] 剩余数据插入出错");
                }
            }
            break;
        }
    }
}

额外性能提升建议

  • 引入EF批量扩展库:如果允许使用第三方库(如Z.EntityFramework.Extensions.EFCore),可直接调用BulkInsert方法,生成数据库原生批量插入语句,性能可提升数倍
  • 数据库层面优化:插入前临时关闭表的非必要索引与约束,插入完成后重建;开启SQL Server的SET NOCOUNT ON减少网络交互
  • 并行处理多文件:若存在多个待处理JSON文件,可使用并行任务同时处理不同文件(单文件流式读取不建议并行)

内容的提问来源于stack exchange,提问作者Janeth Jackson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 11:50:13