2016-05-31 2 views
1

LINQ를 통해 약 150,000 개의 행을 데이터베이스에 저장하는 콘솔 어플리케이션이 있습니다. 이것은 잘 작동합니다 (정상적으로 작동을 멈출 것으로 예상하는 곳). 변화가 CSV 파일에서 데이터를 읽은 후 전화 저장이 늪지 표준입니다 : -LINQ SaveChanges() 예외적으로 느림

List<Invoice> oldInvoices = db.Invoices.Where(x => !x.IsVisible).ToList(); 
List<int> oldInvoiceIDs = oldInvoices.Select(s => s.InvoiceID).ToList(); 

List<InvoiceProduct> allInvoiceProducts = db.InvoiceProducts.ToList(); 
List<InvoiceProduct> oldInvoiceProducts = allInvoiceProducts.Where(x => oldInvoiceIDs.Contains(x.InvoiceID)).ToList(); 

db.InvoiceProducts.RemoveRange(oldInvoiceProducts); 
db.Invoices.RemoveRange(oldInvoices); 

UpdateConsole.WriteLine("Switching over invoices completed. Please wait...", ConsoleColor.Black, ConsoleColor.Magenta); 

표는 각 송장에 대한 제품의 하위 연결된 테이블과 송장의 목록입니다. 새로운 데이터를 얻을 때마다 새로운 데이터를 쓰고 보이지 않는 상태로 데이터베이스에 표시 한 다음 현재 표시된 데이터를 보이지 않게 전환하고 현재 보이지 않는 데이터를 표시되도록 설정하여 하나의 데이터 세트에서 다음 데이터 세트. 이제는 보이지 않는 것으로 표시된 데이터 세트가 LINQ를 통해 삭제됩니다.

시간이 오래 걸리지 만 부당한 시간은 아닙니다. 이 데이터는 CSV 데이터 파일에서 가져온 것이므로 행 수, 파일 읽기 시작 및 종료 날짜 및 시간을 기록합니다.

importLog.SuccessfullyImportedRows = successfulRows; 
importLog.FailedImportedRows = failedRows; 
importLog.EndTime = DateTime.Now; 

db.SaveChanges(); 

이 저장 40 분 초과 을 받아 내가 왜 아무 생각도 없어 -이 다른 데이터베이스 테이블 및 저장 코드에 저장되어 있습니다. 내가 생각할 수있는 유일한 것은 Visual Studio에서 EDMX를 생성 할 때 사용할 수있는 동일한 DBEntities 클래스를 사용하고 있다는 것입니다.

아무도 없습니까? 이 응용 프로그램 매달려의 모양을 제공하지만 ... 40분 정도 후 계속 않습니다

+0

[가능한 빨리 수행 할 수있는 방법] (http://stackoverflow.com/questions/37374480/how-can-i-run-this-task-faster) – Veverke

+0

http : // 도움이 될 수 있습니다. stackoverflow.com/questions/37096509/why-getting-data-with-entity-framwork-is-slow – mohsen

+0

거기에 링크 주셔서 감사합니다. 후자는 루프 내에서 SaveChanges()에 관한 것이고, 내에서는 그렇지 않습니다. 또한 177,000 개의 레코드를 저장할 때 로컬 목록에 저장 한 다음 AddRange()를 실행 한 다음 SaveChanges()를 수행합니다. 목록을 저장하기 위해 SaveChanges()를 한 번만 호출하고 로그를 저장하기 위해 두 번째로 SaveChanges()를 호출합니다. 동일한 문제가 루프 된 SaveChanges() 없이도 여전히 존재할 수 있습니까? –

답변

1

여러 성능 당신의 접근 방식에 문제가 : 데이터베이스에서 불필요한 데이터를 드래그

  1. 합니다.
  2. 대용량 레코드 용 대량 삽입
  3. Hude 레코드에서 대량 삭제.

다음 데이터베이스에서 모든 송장을 드래그하면 데이터베이스에서 직접 조회하고 원하는 목록 만 retreive 수있는 메모리에 로컬로 필터링 할 필요가 없습니다.

는이 작업을 대체해야합니다

List<InvoiceProduct> allInvoiceProducts = db.InvoiceProducts.ToList(); 
List<InvoiceProduct> oldInvoiceProducts = allInvoiceProducts.Where(x => oldInvoiceIDs.Contains(x.InvoiceID)).ToList(); 

로 :

List<InvoiceProduct> oldInvoiceProducts = db.InvoiceProducts.Where(x => oldInvoiceIDs.Contains(x.InvoiceID)).ToList(); 

대량 들어 빠르게 접근 방식을 삭제

String commaDelimitedIds = String.Join(",", oldInvoiceIDs); 
String query = "DELETE FROM Invoice WHERE InvoiceID IN (" + commaDelimitedIds + ")"; 
db.ExecuteQuery(query); 

Linq To SQL를 통해 150,000 recod를 삽입하는 것은 좋은 생각이 아니다, 그러면 150,000가 생성됩니다. 10 성명 (관계 객체를 언급하는 데는 아니오).

거대한 인서트에 이상적인이 예제를 보겠습니다. SQLBulkCopy.

일반적으로 ORM 은 대량 작업에 적합하지 않습니다.

+0

안녕하세요. 답장을 보내 주셔서 감사합니다. 당신은 데이터베이스에서 불필요한 데이터를 끌고 있다고 말하는 것이 맞습니다. "with :"뒤에 나오는 세 번째 코드 줄은 .Contains()에 너무 많은 정수가 있기 때문에 오류가 발생했습니다. 그래서 나는 여분의 라인에서 지역 목록을 선택한 다음 위의 방법을 사용했다. 도움을 많이 주셔서 감사합니다! 나는 그것을 줄 것이다. –

+1

@MikeUpjohn for 루프를 사용하여 2000 개의 ID를 함께 나눌 수 있으며, 마지막에 함께리스트를 '연결'합니다. 이것은 SQL 매개 변수 제한에 대한 해결책입니다. – user3185569

1

우선, 귀하의 질문에 .toList()을 사용할 때 문제가 있음을 압니다. toList은 해당 쿼리를 즉시 실행하고 메모리에 저장한다는 것을 의미합니다.소규모 데이터의 경우 더 빠르지 만 150,000 개가 넘는 행의 경우 성능에 문제가 생기고 기억이 부족합니다. 대신 AsQueryable()을 사용할 수 있습니다.

AsQueryable은 단지 쿼리를 생성하는데 지침은 목록을 가져 오는 데 필요합니다. new where 절을 데이터베이스 수준까지 계속 추가하는 것과 같이 나중에 쿼리를 더 많이 변경할 수 있습니다.

EF 6 이상인 경우 RemoveRange의 성능이 매우 빠릅니다. 그래서 RemoveRange이 근본 원인이라고 생각하지 않습니다. 그러나 더 많은 성능을 향상 시키려면이 확장 기능을 사용해보십시오. 정말 좋습니다. https://efbulkinsert.codeplex.com/

0

좋아, 내가 찾은 해결책 (추론에는 확실하지 않음). 내가 로깅 기능에 엔티티 항목을하지 않고 내가 할 경우 EDMX에서 생성 된 엔터티의 새 인스턴스가

이 초 미만에서 작동
using(DBEntities db = new DBEntities()) { 
    importLog.SuccessfullyImportedRows = successfulRows; 
    importLog.FailedImportedRows = failedRows; 
    importLog.EndTime = DateTime.Now; 

    db.SaveChanges(); 
} 

을 e.g.:-. DBEntities의 원래 인스턴스에서 많은 행을 삽입하는 것으로 캐시되는 것이 있습니까?