EF Core Медленная массовая вставка (~ 80 тыс. Строк) - PullRequest
3 голосов
/ 28 января 2020

У меня есть 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 со всеми связанными коллекциями, добавляя до 80 тыс. Объектов, ни один из которых не присутствует в базе данных.

Затем, когда я вызываю dbContext.Add(save), это занимает около 44 секунд, чтобы процесс, с использованием ОЗУ, увеличивающимся с 100 МБ до примерно 700 МБ.

Затем, когда я вызываю dbContext.SaveChanges() (я также попробовал обычный метод BulkSaveChanges() из EF Extensions без существенной разницы), требуется дополнительные 60 с. , с использованием оперативной памяти до 1,3 ГБ.

Что здесь происходит? Почему так долго и так много использования памяти? Фактическая загрузка в базу данных занимает всего около 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();
        }
        [...]
    }

}

Ответы [ 2 ]

0 голосов
/ 29 января 2020

Загрузить EFCore.BulkExtensions из нюгетов

Удалить "_db.BulkSaveChanges ();" и замените "_db.Saves.Add (save);" с этим кодом

_db.Saves.BulkInsert(save);
0 голосов
/ 28 января 2020

РЕДАКТИРОВАТЬ: 1. Убедитесь, что проблема не в БД.

Выполните собственную команду, чтобы увидеть, как быстро она работает.

Сохраняйте активный граф контекста небольшим, используя новый контекст для каждой единицы работы, также попробуйте отключить AutoDetechChangesEnabled

3. пакетное количество команд вместе

Здесь хорошая статья о Entity Framework и медленных массовых вставках

...