[MSSQL] 대량의 Data를 DB에 삽입하는 방법
1. 개요
매일 자정마다 수많은 데이터를 가진 Table을 원격 DB에서 끌어다 와서 관리하는 DB로 복제하는 작업을 수행해야 했다.
하지만 매일 자정마다 복제하는 데이터의 크기가 자그마치 10~20만개 수준이었고, 이를 일일히 insert하면 약 16시간이라는 절망적인 퍼포먼스를 낳게 되어, 개선 방안을 강구하게 되었다.
2. 1차 개선 방법
우선은 현재 관리하는 DB와 원격 DB의 데이터들 중에 동일한 데이터들은 복제를 하지 않아도 된다.
이를 이용하여 원격 DB에서 가져온 데이터와 현재 관리하는 DB에서 가져온 데이터를 대조하여, 코드상에서 완전히 동일한 레코드는 C#코드에서 필터링 하는 로직을 추가하였다.
하지만 이는 추가적인 시간 소모를 불러일으켰다.
복제할 데이터들과 원본 데이터가 각각 10만개 이상의 레코드를 가지고 있다면,
각각의 데이터에 대해 같은 데이터가 있는지 찾는데에 10만 * 10만의 기하급수적인 시간 소요가 일어난다.
그래서 이 필터링 로직을 수행 시 시스템의 프로세스가 병렬로 수행되도록 하였고, 시스템 리소스는 조금 더 많이 사용하더라도 빠른 퍼포먼스를 낼 수 있도록 하였다.
(병렬화 수행을 기본적으로 수행하면, 메모리를 100% 점유하여 시스템이 먹통이 되기에, 아래와 같이 프로세스의 3/4만 사용하도록 제한을 두어 수행하였다.)
그 결과.. 13만개 X 13만개의 데이터를 대조하여 필터링 하면 75000개의 필터된 데이터가 나와서 이를 가지고 insert를 수행한다.
필터링하는데에는 약 5분정도 소요되나, 여전히 많은 수의 데이터여서 일일히 insert를 날려주기에는 7~8시간이라는 너무 긴 시간이 소요되었다.
3. 2차 개선 방법
최대한 MSSQL에서 제공하는 대용량 데이터를 처리할 수 있는 로직을 사용해보자.
C#에서도 받은 대용량의 데이터들을 효율적으로 insert하는 방법을 찾아보기로 하였다.
그 결과, System.Data 네임스페이스의 DataTable 인스턴스를 만들어서 BulkCopy할 수 있는 방법이 있다는걸 알게 되었고, 검증한 결과 이는 엄청난 퍼포먼스 향상을 일으킨다는 것을 알아냈다.
[DataTable 생성]
[Bulk Insert 수행]
DB의 Connection string과 tableName, 그리고 위에서 만든 DataTable 타입의 파라미터를 받아서 해당 DB 내 Table에 BulkInsert를 수행한다.
[위의 작업들을 호출 (DataTable 생성 후 Bulk Insert)]
우선 Bulk Data를 임시로 받을 Table을 정의하자.
아래와 같이 간단한 쿼리로 테이블의 구조만 복제하는 작업을 수행할 수 있다.
SELECT * INTO <DESTINATION> FROM <SOURCE_TABLE> WHERE 1=2
(* Default value값과 같은 설정은 복제되지 않는 것으로 확인된다. 테이블의 그 외 설정들이 있다면 복제 후 점검이 필요해 보인다.)
그 후, 위의 C#로직을 통해서 SqlBulkCopy를 수행하여 임시 테이블에 대용량 데이터들을 단시간에 삽입시키고,
MSSQL의 쿼리를 이용하여 데이터들이 올라간 임시 테이블과 삽입 대상 테이블의 데이터를 대조하여 Update 및 Insert를 수행해주면 된다.
이는 MERGE INTO문으로 단순히 수행이 가능하다.
Source Table과 Destination Table을 주고, 각각의 데이터들을 판별할 row를 주어 분별한 후,
Match된다면 Update, Not Match된다면 Insert하는 식으로 수행할 수 있다.
(추가 분기도 가능하다. MERGE문 참고 사이트: microsoft guide)
그 결과..
이전에 7~8시간은 족히 걸리던 프로세스가 단 15초만에 수행되는 결과를 낳았다.
단순히 생각하면 바로 고칠 수 있었으나.. 다른 일로 인해 경황이 없어 이제야 해결을 하게 되었다..^^
MSSQL은 DB System이기에 대용량 데이터를 관리할 방법이 꼭 제공되어 있을테고,
.NET과 MSSQL간 대용량 데이터 처리 방법도 찾아보면 이렇게 나올텐데, 같은 동작을 수행하더라도 지난 나날 리소스를 불필요히 과소비하게 두었구나 돌아보게 되었다.