ABP框架中InsertMany批量插入7万+数据速度极慢求助
ABP + EF Core 批量插入性能优化方案
针对你遇到的7万条数据批量插入慢、批次递增耗时变长的问题,以下是具体解决办法:
1. 关闭变更跟踪与自动检测
EF Core默认会跟踪所有添加的实体,批量插入时这会产生巨大的性能开销。在批量操作中临时关闭相关功能:
using (var uow = _unitOfWorkManager.Begin()) { var dbContext = _dbContextProvider.GetDbContext(); // 关闭自动变更检测与实体验证 dbContext.ChangeTracker.AutoDetectChangesEnabled = false; dbContext.ValidateOnSaveEnabled = false; dbContext.Set<YourEntity>().AddRange(batchEntities); await dbContext.SaveChangesAsync(); // 恢复默认设置 dbContext.ChangeTracker.AutoDetectChangesEnabled = true; dbContext.ValidateOnSaveEnabled = true; await uow.CompleteAsync(); }
2. 清理变更跟踪避免批次变慢
每批次插入后,EF仍会保留实体的跟踪信息,导致后续批次内存占用和处理时间递增。每次批次完成后清理跟踪:
await dbContext.SaveChangesAsync(); dbContext.ChangeTracker.Clear(); // 清理已跟踪的实体
3. 临时关闭ABP审计日志
ABP默认开启的审计日志会记录每一条插入操作,批量场景下会生成大量日志拖慢速度。在UnitOfWork中临时禁用:
using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions { IsTransactional = true, DisableAuditing = true // 关闭审计 })) { // 批量插入逻辑 await uow.CompleteAsync(); }
4. 使用原生SQL批量插入(TVP方式)
通过SQL Server的表值参数(Table-Valued Parameter)实现高效批量插入,避开EF的ORM开销:
- 先在SQL Server中创建用户定义表类型:
CREATE TYPE dbo.YourEntityType AS TABLE ( Property1 NVARCHAR(100), Property2 INT, -- 其他对应字段 )
- 代码中构造DataTable并执行原生SQL:
var dataTable = new DataTable(); dataTable.Columns.Add("Property1", typeof(string)); dataTable.Columns.Add("Property2", typeof(int)); // 填充数据到DataTable foreach (var entity in batchEntities) { dataTable.Rows.Add(entity.Property1, entity.Property2); } await _dbContext.Database.ExecuteSqlRawAsync( @"INSERT INTO YourEntities (Property1, Property2) SELECT Property1, Property2 FROM @tvp", new SqlParameter("@tvp", SqlDbType.Structured) { TypeName = "dbo.YourEntityType", Value = dataTable } );
5. 使用EFCore.BulkExtensions扩展
EF Core本身没有内置BulkInsert,你可以通过第三方库实现,ABP不会限制这个功能:
- 安装NuGet包:
Install-Package EFCore.BulkExtensions - 在UnitOfWork中直接调用:
using (var uow = _unitOfWorkManager.Begin()) { var dbContext = _dbContextProvider.GetDbContext(); await dbContext.BulkInsertAsync(batchEntities); await uow.CompleteAsync(); }
6. 其他优化建议
- 调整批次大小:测试1000-5000条的批次规模,找到适合你环境的最优值;
- 临时禁用非聚集索引:插入前禁用表上的非聚集索引,完成后重建,减少插入时的索引维护开销;
- 简化实体关联:批量插入时尽量避免加载或关联复杂导航属性,减少EF的额外处理逻辑。
内容的提问来源于stack exchange,提问作者Adrian Inman
相关产品推荐
相关产品推荐

