EF 코어 저속 벌크 인서트(80k 행까지)
나는 가지고 있다Save
여러 컬렉션이 연결된 개체입니다.개체의 총 크기는 다음과 같습니다.
오브젝트 간의 관계는 이 매핑에서 얻을 수 있으며 데이터베이스에서 올바르게 표현된 것으로 보입니다.쿼리도 문제없이 작동합니다.
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,000개의 개체를 추가하지만 데이터베이스에 존재하지 않습니다.
그럼, 내가 전화했을 때dbContext.Add(save)
처리에는 약 44초가 소요되며 RAM 사용량은 100MB에서 약 700MB로 증가합니다.
그럼, 내가 전화했을 때dbContext.SaveChanges()
(레귤러도 해봤는데BulkSaveChanges()
큰 차이가 없는 EF Extensions의 방식)에 따라 추가로 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();
}
[...]
}
}
EFCore를 다운로드합니다.Nugets로부터의 Bulk Extensions
'_db'를 삭제합니다.Bulk Save Changes();"를 입력하고 "_db"를 바꿉니다.Saves.Add(save);" 이 코드와 함께
_db.Saves.BulkInsert(save);
편집: 1. 문제의 원인이 DB가 아님을 확인합니다.
자체 명령을 실행하여 실행 속도를 확인합니다.
- 각 작업단위에 대해 새 컨텍스트를 사용하여 활성 컨텍스트 그래프를 작게 유지하고 AutoDetechChangesEnabled를 끄십시오.
3. 다수의 명령어를 조합하다
엔티티 프레임워크와 느린 벌크 INSERT에 대한 좋은 기사를 소개합니다.
N을 봐주셨으면 합니다.EntityFrameworkCore내선번호EFCore 6.0.8+용 벌크 확장 프레임워크입니다.
Install-Package N.EntityFrameworkCore.Extensions
https://www.nuget.org/packages/N.EntityFrameworkCore.Extensions
nuget 패키지를 설치하면 DbContext 인스턴스에서 BulkInsert() 메서드를 직접 사용할 수 있습니다.BulkDelete, BulkInsert, BulkMerge 등을 지원합니다.
BulkDelete()
var dbcontext = new MyDbContext();
var orders = dbcontext.Orders.Where(o => o.TotalPrice < 5.35M);
dbcontext.BulkDelete(orders);
일괄 삽입()
var dbcontext = new MyDbContext();
var orders = new List<Order>();
for(int i=0; i<10000; i++)
{
orders.Add(new Order { OrderDate = DateTime.UtcNow, TotalPrice = 2.99 });
}
dbcontext.BulkInsert(orders);
언급URL : https://stackoverflow.com/questions/59954097/ef-core-slow-bulk-insert-80k-rows
'itsource' 카테고리의 다른 글
JavaScript에서 여러 CSS 스타일을 설정하려면 어떻게 해야 합니까? (0) | 2022.09.14 |
---|---|
PHP가 $_GET 또는 $_POST 배열에서 '.' 문자의 치환을 중지하도록 합니다. (0) | 2022.09.14 |
MySQL 일부 외부 키 제거 (0) | 2022.09.14 |
PHP를 사용하여 IP 주소 국가 가져오기 (0) | 2022.09.13 |
JPA: 대규모 결과 세트에 대해 반복하기 위한 적절한 패턴은 무엇입니까? (0) | 2022.09.13 |