EF Core使用IncludeGraph做BulkInsert到SQL Server速度慢如何优化?
EF Core Bulk Extensions 大批量对象图插入性能优化方案
调整BulkInsert运行参数
- 调整
BatchSize到2000~5000区间测试最优值,同步设置BulkCopyTimeout = 0(不限制超时),当前1000的批次偏小,会增加批量提交的总次数 - 显式配置批量操作开关,关闭不需要的逻辑:
BulkInsert(entities, o => { o.IncludeGraph = true; o.UseTempDB = true; o.AutoMapOutputIdentity = true; o.InsertIfNotExists = false; });UseTempDB可以降低对象图关联匹配时的磁盘IO开销,你后续统一做去重,不需要插入时判断重复,关闭InsertIfNotExists可减少30%左右的计算开销 - 如果对象图层级不超过3级,额外开启
o.IncludeGraphSingleSession = true,减少上下文切换开销
SQL Server端优化
- 插入前临时删除所有非聚集索引,插入完成后统一重建:插入过程中维护非聚集索引的开销会占到总写入开销的60%以上,你当前每个导航属性都对应非聚集索引,这是核心性能瓶颈之一
- 插入阶段临时关闭外键约束检查,插入完成后再恢复:
你后续会做数据清理,插入阶段的外键检查属于完全冗余开销-- 关闭指定表所有外键约束 ALTER TABLE [表名] NOCHECK CONSTRAINT ALL -- 插入完成后恢复 ALTER TABLE [表名] CHECK CONSTRAINT ALL - 调整数据库文件自动增长策略:将数据文件、日志文件的自动增长步长设置为1GB,避免默认10%增长策略带来的频繁文件扩容锁
- 确认数据库文件存放在SSD介质上,机械盘的顺序写入性能比SSD低5~10倍,会直接拖慢批量插入速度
程序端优化
- 每个插入批次单独创建DbContext,用完立即释放,避免上下文跟踪的实体数量持续增长,导致内存占用过高、实体匹配效率下降
- 批次内提前做子实体去重:对同一批次内的子实体按唯一键做Hash去重,避免重复写入临时表,减少数据传输和计算开销
- 开启服务器GC模式,在项目.csproj文件中添加配置:
大内存场景下可大幅降低GC停顿时间,提升多线程处理效率<PropertyGroup> <ServerGarbageCollection>true</ServerGarbageCollection> </PropertyGroup>
极端性能场景优化方案
如果以上调整后仍达不到预期,可放弃IncludeGraph自动处理逻辑,改为手动拆分实体插入:
- 先批量插入所有根实体,获取生成的自增主键
- 关联根主键后批量插入一级子实体,获取子实体主键
- 以此类推处理所有层级的实体
该方式比IncludeGraph自动处理速度快2~3倍,但需要自行实现主键映射逻辑
内容的提问来源于stack exchange,提问作者Martin Kirk
相关产品推荐
相关产品推荐

