c# - EF Core 慢速批量插入(约 80k 行)

标签 c# entity-framework entity-framework-core mariadb ef-core-3.1

我有一个 Save 对象,它有多个关联的集合。对象的总大小如下:

enter image description here

对象之间的关系可以从该映射中推断出来,并且在数据库中似乎得到了正确的表示。查询也很好。

modelBuilder.Entity<Save>().HasKey(c => c.SaveId).HasAnnotation("DatabaseGenerated",DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Save>().HasMany(c => c.Families).WithOne(x => x.Save).HasForeignKey(x => x.SaveId);
modelBuilder.Entity<Save>().HasMany(c => c.Countries).WithOne(x => x.Save).HasForeignKey(x => x.SaveId);
modelBuilder.Entity<Save>().HasMany(c => c.Provinces).WithOne(x => x.Save).HasForeignKey(x => x.SaveId);
modelBuilder.Entity<Save>().HasMany(c => c.Pops).WithOne(x => x.Save).HasForeignKey(x => x.SaveId);
modelBuilder.Entity<Country>().HasOne(c => c.Save);
modelBuilder.Entity<Country>().HasMany(c => c.Technologies).WithOne(x => x.Country).HasForeignKey(x => new {x.SaveId, x.CountryId});
modelBuilder.Entity<Country>().HasMany(c => c.Players).WithOne(x => x.Country).HasForeignKey(x => new {x.SaveId, x.CountryId});
modelBuilder.Entity<Country>().HasMany(c => c.Families).WithOne(x => x.Country).HasForeignKey(x => new {x.SaveId, x.OwnerId});
modelBuilder.Entity<Country>().HasMany(c => c.Provinces).WithOne(x => x.Owner);
modelBuilder.Entity<Country>().HasKey(c => new { c.SaveId, c.CountryId });
modelBuilder.Entity<Family>().HasKey(c => new { c.SaveId, c.FamilyId });
modelBuilder.Entity<Family>().HasOne(c => c.Save);
modelBuilder.Entity<CountryPlayer>().HasKey(c => new { c.SaveId, c.CountryId, c.PlayerName });
modelBuilder.Entity<CountryPlayer>().HasOne(c => c.Country);
modelBuilder.Entity<CountryPlayer>().Property(c => c.PlayerName).HasMaxLength(100);
modelBuilder.Entity<CountryTechnology>().HasKey(c => new { c.SaveId, c.CountryId, c.Type });
modelBuilder.Entity<CountryTechnology>().HasOne(c => c.Country);
modelBuilder.Entity<Province>().HasKey(c => new { c.SaveId, c.ProvinceId });
modelBuilder.Entity<Province>().HasMany(c => c.Pops).WithOne(x => x.Province);
modelBuilder.Entity<Province>().HasOne(c => c.Save);
modelBuilder.Entity<Population>().HasKey(c => new { c.SaveId, c.PopId });
modelBuilder.Entity<Population>().HasOne(c => c.Province);
modelBuilder.Entity<Population>().HasOne(c => c.Save);

我从文件中解析整个save,因此无法一一添加所有集合。解析后,我有一个包含所有关联集合的Save,添加了多达 80k 个对象,但这些对象都不存在于数据库中。

然后,当我调用 dbContext.Add(save) 时,处理时间大约为 44 秒,RAM 使用量从 100mb 上升到大约 700mb。

然后,当我调用 dbContext.SaveChanges() (我还尝试了 EF 扩展中的常规 BulkSaveChanges() 方法,没有显着差异)时,需要额外的 60 秒,RAM 使用量高达 1.3Gb。

这是怎么回事?为什么这么长的时间和这么多的内存使用量?实际上传到数据库只需要最后5秒左右。

PS:我也尝试禁用更改检测,但没有效果。

PS2:实际使用情况和评论中要求的完整代码:

public class HomeController : Controller
{
    private readonly ImperatorContext _db;

    public HomeController(ImperatorContext db)
    {
        _db = db;
    }

    [HttpPost]
    [RequestSizeLimit(200000000)]
    public async Task<IActionResult> UploadSave(List<IFormFile> files)
    {
        [...]
        await using (var stream = new FileStream(filePath, FileMode.Open))
        {
            var save = ParadoxParser.Parse(stream, new SaveParser());
            if (_db.Saves.Any(s => s.SaveKey == save.SaveKey))
            {
                 response = "The save you uploaded already exists in the database.";
            }
            else
            {
                 _db.Saves.Add(save);
            }
            _db.BulkSaveChanges();
        }
        [...]
    }

}

最佳答案

从 nuget 下载 EFCore.BulkExtensions

删除“_db.BulkSaveChanges();”并替换“_db.Saves.Add(save);”使用此代码

_db.Saves.BulkInsert(save);

关于c# - EF Core 慢速批量插入(约 80k 行),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59954097/

相关文章:

c# - 在任务中报告/记录

c# - 当发生错误时,我们如何从ServiceStack的JSON Serializer访问数据?

c# - Entity Framework 核心中的postgres查询问题

entity-framework - EF Core 2.0/2.1 - 如何有效地处理不常访问的大型列?

c# - Entity Framework Core 表拆分方法

c# - 在 DataGridView 中读取 CSV 文件

c# - 从Azure Redis缓存插入或删除值时,是否需要在代码级别进行同步?

c# Lambda 查询奇怪地获取属性之一 null

entity-framework - 未找到具有不变名称 'System.Data.SqlServerCe.4.0' 的 ADO.NET 提供程序的 Entity Framework 提供程序

c# - Entity Framework Core - 防止唯一索引上出现多个空值