Dapper를 통한 대량 삽입은 행을 하나씩 삽입하는 것보다 느립니다.

.net batch-insert dapper sql-server

문제

Dapper를 사용하여 실시간 피드의 데이터를 SQL Server에 삽입하므로 성능이 중요합니다. 최근에 나는 이상한 것을 발견했다.
Dapper에게 컬렉션과 삽입 쿼리를 제공하면 각 요소에 대한 insert 문이 실행됩니다. 내 테스트에 따르면 약 1800 개의 객체를 1 초에 12 개의 필드로 삽입 할 수 있다는 것을 알 수 있습니다 ( connection.Execute(...) 실행 시간 만 계산 connection.Execute(...) .
이제, Dapper에서 배치 삽입 기능을 찾지 못해서 내 자신을 구현했습니다 (매개 변수 목록 및 SQL 쿼리 구성). 그 후 약 3 초 만에 하나의 배치를 삽입 할 수 있다는 것을 알았습니다. (이는 1000 행으로 제한됩니다.) 다시 한번 connection.Execute(...) 호출 만 계산합니다.
따라서 각 행을 별도의 쿼리로 보내는 것보다 일괄 처리 속도 가 거의 6 배 느려집니다 . 누군가 나에게 설명해 줄 수 있니? 나는 사람들이 배치 작업을 사용하여 프로세스 속도를 높이는 것을 생각했습니다.
삽입 시간을 최대 1 초로하고 싶습니다. 로컬 네트워크에있는 SQL Server 2012 Standard를 사용합니다. 삽입 할 테이블은 기본 키 (bigint 필드)에 클러스터 된 인덱스가 있고 클러스터되지 않은 인덱스와 트리거는 없습니다.
코드를 게시 할 수는 있지만 실제로 특별한 것은 없습니다.

전문가 답변

최고의 성능을 원한다면 왜 Dapper Execute 확장 방법을 사용하는지 잘 모르겠습니다.

최고의 성능으로 삽입하는 가장 좋은 방법은 SqlBulkCopy 클래스를 직접 사용하는 것입니다.

면책 조항 : 저는 Dapper Plus 프로젝트의 소유자입니다.

이 프로젝트는 다음 작업을 쉽게 지원합니다.

  • 대량 삽입
  • 대량 업데이트
  • 벌크 삭제
  • 벌크 머지

예:

// CONFIGURE & MAP entity
DapperPlusManager.Entity<Order>()
                 .Table("Orders")
                 .Identity(x => x.ID);

// CHAIN & SAVE entity
connection.BulkInsert(orders)
          .AlsoInsert(order => order.Items);
          .Include(x => x.ThenMerge(order => order.Invoice)
                         .AlsoMerge(invoice => invoice.Items))
          .AlsoMerge(x => x.ShippingAddress);   

인기 답변

이상적인 배치 크기는 서버마다 다를 수 있습니다. 핵심 요소는 로깅입니다. 이는 인서트의 리소스 집약 방법과 성능 저하가 발생하기 전에 배치를 만들 수있는 크기에 영향을 미칩니다.

신속한 삽입 / 업데이트의 핵심은 최소 로깅 요구 사항을 충족하는지 확인하는 것입니다.이 Microsoft 백서를 참조하십시오 . 당황하지 마십시오 - 모든 것을 읽을 필요는 없습니다 - 최소 로깅을 충족시키는 조건을 설명하는 표를보십시오 (DBA와상의해야합니다).

가능한 한 적은 로깅을 가지면 SPOOLS의 실행 계획을 살펴볼 필요가 있습니다. 배치가 Tempdb에 스풀되기 시작하면 극적으로 느려집니다. 핵심은 버퍼 (RAM)에 남아있을만큼 배치를 작게 유지하는 것입니다. 그러나 사용 가능한 버퍼 공간의 양은 다른 프로세스에 따라 달라집니다.

참고 : TABLOCK은 TABLOCKX와 다릅니다.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow