Bulk Insert, 성능 테스트

2022. 3. 5. 19:17BACKEND/Database

반응형

데이터베이스 쿼리의 성능을 높이는 방법으로 Bulk Insert를 사용하곤 하는데요.

 

오늘은 데이터베이스의 Bulk Insert의 성능을 비교해보고자 합니다.

직접 실행해본 쿼리를 통해 어느정도 성능이 좋아지는 지를 직접 확인해보기 위함입니다.

 

+ 스프링에서 사용하는 MyBatis에 대한 코드로의 테스트도 함께 진행합니다.

 

이어지는 포스팅

👉🏻  Spring, Bulk Insert 성능 측정 

 

Bulk Insert

Bulk는 무더기, 더 나눠지지 않는 대량의 짐 등으로 볼 수 있습니다.

데이터들이 무수히 많은 경우의 데이터 삽입 시에 이 Bulk Insert를 사용합니다.

따로 어려운 개념이 아니라, Insert 쿼리만을 조금 바꾸는 것인데요.

실제로 테스트 해보도록 합시다.

 

참고로, MySQL Workbench에서 테스트를 하려면 connection 정보에서 timeout을 변경하셔야 합니다.

저는 4000정도로 잡았습니다. 기본이 60인가로 설정되어있을 거에요.

 

Stored Procedure

SP는 일련의 쿼리를 마치 하나의 함수처럼 실행하기 위한 쿼리의 집합입니다.

함수와 같이 특정 로직의 쿼리를 정의해두고 필요할 때 불러와 실행시킬 수 있습니다.

자주 사용하는 쿼리는 한 번 정의해두고 재사용할 수 있다는 장점이 있으며,

옵티마이저의 최적화의 비용도 줄일 수 있죠.

 

아래는 SP로 생성한 쿼리입니다.

 

 

BASIC INSERT

DELIMITER $$ 
DROP PROCEDURE IF EXISTS BASIC_INSERT;
CREATE PROCEDURE BASIC_INSERT()
BEGIN
 DECLARE i INT DEFAULT 0;
 DECLARE lo INT DEFAULT 100000;
 WHILE( i < lo) DO
  INSERT INTO test(NAME, email, PASSWORD) 
  VALUES(
   CONCAT("gngsn", i), 
   CONCAT(i, "@email.com"), 
   UUID()
  );
  SET i = i+1;
 END WHILE;
END $$
DELIMITER ;

 

BASIC_INSERT 프로시저를 정의하고, 

100,000 건의 데이터를 추가하는 테스트입니다.

 

정의 후 실행합니다.

 

mysql> CALL BASIC_INSERT;
Query OK, 1 row affected (28.11 sec)

 

Duration이 28.11초 라는 것을 확인할 수 있습니다.

 

이번엔 BULK INSERT를 정의해보도록 할게요.

 

 

BULK INSERT

BULK INSERT는 INSERT를 하나하나 실행하는 것이 아니라, 

INSERT INTO .. VALUES (), () 형식으로 실행합니다. 

BULK라는 이름에 맞게 한 번에 모아서 추가하는 동작입니다.

 

DELIMITER $$ 
DROP PROCEDURE IF EXISTS BULK_INSERT$$
CREATE PROCEDURE BULK_INSERT()
BEGIN
 DECLARE i INT DEFAULT 1;
 DECLARE lo INT DEFAULT 100000/10;
 WHILE(i <= lo) DO
  INSERT INTO test(NAME, email, PASSWORD) VALUES
  (CONCAT("gngsn", i), CONCAT(i, "@bulk.com"), UUID()),
  (CONCAT("gngsn", i+1), CONCAT(i+1, "@bulk.com"), UUID()), 
  (CONCAT("gngsn", i+2), CONCAT(i+2, "@bulk.com"), UUID()), 
  (CONCAT("gngsn", i+3), CONCAT(i+3, "@bulk.com"), UUID()), 
  (CONCAT("gngsn", i+4), CONCAT(i+4, "@bulk.com"), UUID()), 
  (CONCAT("gngsn", i+5), CONCAT(i+5, "@bulk.com"), UUID()), 
  (CONCAT("gngsn", i+6), CONCAT(i+6, "@bulk.com"), UUID()), 
  (CONCAT("gngsn", i+7), CONCAT(i+7, "@bulk.com"), UUID()),
  (CONCAT("gngsn", i+8), CONCAT(i+8, "@bulk.com"), UUID()),
  (CONCAT("gngsn", i+9), CONCAT(i+9, "@bulk.com"), UUID());
  SET i = i+10;
 END WHILE;
END $$
DELIMITER ;

 

총 10건씩을 모아서 한 번에 Insert를 합니다.

실행 시간을 확인해볼까요?

 

mysql> CALL BULK_INSERT();
Query OK, 10 rows affected (3.40 sec)

 

Duration이 3.40초 라는 것을 확인할 수 있습니다.

28.11 초에 비해 약 8배 가량 빠르게 실행된 것을 볼 수 있습니다.

 

굉장히 효율적인 실행 방식이죠.

 

 

Spring MyBatis

실제로, Spring MyBatis를 사용할 때도 이렇게 Bulk Insert를 사용하곤 합니다.

흔히 Batch Insert라고 부르며, 아래와 같이 작성하곤 합니다.

 

<mapper namespace="com.gngsn.demo.UserMapper">
	...
    <insert id="bulkInsertUserList" parameterType="java.util.List">
        INSERT INTO test (name, email, PASSWORD)
        VALUES
        <foreach collection="list" item="item" separator=",">
          (#{item.name}, #{item.email}, #{item.password})
        </foreach>
    </insert>
	...
</mapper>

 

정말 간단히 테스트한 코드를 깃허브에 올려두었으니, 필요하다면 참고바랍니다.

결과만 알려드리면 총 1000건에 대해 아래와 같은 결과를 볼 수 있습니다.

 

Basic Insert Duration : 7266
Bulk Insert Duration : 115

 

 

단위는 ms입니다.

 

반응형

'BACKEND > Database' 카테고리의 다른 글

MySQL FullText Search, 제대로 이해하기  (3) 2022.04.24
SQL Execution Plan, 제대로 이해하기  (2) 2022.04.17
Database Index, 제대로 알아보기  (4) 2021.07.30
SQL, Window Function  (0) 2020.11.29
ERD, 어렵지 않게 만들기  (12) 2020.06.26

Backend Software Engineer

Gyeongsun Park