들어가며
SQL 에서 성능체크 및 쿼리 튜닝을 하려면 테스트를 위한 더미데이터가 필요합니다. 해당 포스팅에서는 이러한 더미 데이터를 보다 쉽게 만들 수 있는 방법을 소개하고자 합니다.
DDL 정의
제일 먼저 테스트 데이터를 저장할 Table 을 만들어주기 위한 DDL 을 아래와 같이 작성합니다.
DROP TABLE IF EXISTS member;
CREATE TABLE member
(
id bigint NOT NULL AUTO_INCREMENT,
nickname varchar(8) NOT NULL,
created_at datetime(6) NOT NULL,
PRIMARY KEY (id)
) ENGINE = InnoDB;
DROP TABLE IF EXISTS crew;
CREATE TABLE crew
(
id bigint NOT NULL AUTO_INCREMENT,
name varchar(45) NOT NULL,
created_at datetime(6) NOT NULL,
updated_at datetime(6) NOT NULL,
PRIMARY KEY (id)
) ENGINE = InnoDB;
DROP TABLE IF EXISTS crew_participant;
CREATE TABLE crew_participant
(
id bigint NOT NULL AUTO_INCREMENT,
crew_id bigint NOT NULL,
member_id bigint NOT NULL,
request_at datetime(6) NOT NULL,
PRIMARY KEY (id)
) ENGINE = InnoDB;
Dummy 데이터 삽입
앞서 만들어준 Table 에 하나하나 insert 쿼리를 여러번 날리는 것은 매우 비효율적입니다. 하지만 Procedure 를 사용하면 이를 개선시켜줄 수 있습니다.
Procedure 는 프로그래밍 언어에서의 Function(함수) 이라고 생각하면 됩니다.
Procedure 생성
프로시저 안에서는 while
문을 사용해서 반복적으로 insert 쿼리를 날려줄 수 있습니다. 사용할 Variable idx 를 1 로 초기화해주고, 각 Loop 마다 초기화된 idx 를 +1 시켜 2000 까지 키워갈 수 있습니다. 따라서 해당 프로시저에서는 member
테이블에 2000
개의 row 가 삽입되게 됩니다.
DELIMITER $$
DROP PROCEDURE IF EXISTS member_loop $$
CREATE PROCEDURE member_loop()
BEGIN
DECLARE idx INT DEFAULT 1;
WHILE idx <= 2000
DO
INSERT INTO member(nickname, created_at)
VALUES
(CONCAT('n_', idx), NOW());
SET idx = idx + 1;
END WHILE;
END $$
DELIMITER ;
아래 프로시저도 마찬가지입니다. 아래의 프로시저는 crew
테이블에 2000
개의 row 를 삽입하게 됩니다.
DELIMITER $$
DROP PROCEDURE IF EXISTS crew_loop $$
CREATE PROCEDURE crew_loop()
BEGIN
DECLARE idx INT DEFAULT 1;
WHILE idx <= 2000
DO
INSERT INTO crew(name, created_at, updated_at)
VALUES
(CONCAT('n_', idx), NOW(), NOW());
SET idx = idx + 1;
END WHILE;
END $$
DELIMITER ;
아래 프로시저는 좀 복잡해 보이지만 별로 다를게 없습니다. 단지, member 와 crew 의 총 개수를 변수로 할당해주고, 2중 While 문을 사용했을 뿐입니다. 따라서 crew_participant
테이블에는 총 400 만개
의 row 를 삽입하게 됩니다.
해당 작업은 매우 오래걸리는 작업입니다. 400 만개를 insert 하는 시간은 맥북 M3 Pro 기준 20 분이 소요되었습니다. 해당 쿼리는 5000 개 정도로 끊어서 batch insert 하는 방향으로 최적화 시킬 수있을 것 같습니다.
DELIMITER $$
DROP PROCEDURE IF EXISTS crew_participant_loop $$
CREATE PROCEDURE crew_participant_loop()
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE j INT DEFAULT 1;
SET @member_count = ( SELECT COUNT(id) FROM member );
SET @crew_count = ( SELECT COUNT(id) FROM crew );
WHILE i <= @member_count
DO
SET j = 1;
WHILE j <= @crew_count
DO
INSERT INTO crew_participant(crew_id, member_id, request_at) VALUES (i, j, NOW());
SET j = j + 1;
END WHILE;
SET i = i + 1;
END WHILE;
END $$
DELIMITER ;
Procedure 실행
앞서 정의한 member_loop
, crew_loop
, crew_participant_loop
프로시저는 CALL
예약어로 실행시킬 수 있습니다.
CALL member_loop;
CALL crew_loop;
CALL crew_participant_loop;
결과 확인
3 개의 프로시저를 모두 수행하면 차례대로 2000, 2000, 4000000
개의 데이터가 insert 되어있는 것을 확인할 수 있습니다.
SELECT COUNT(id) FROM member
UNION ALL SELECT COUNT(id) FROM crew
UNION ALL SELECT COUNT(id) FROM crew_participant;
마치며
테스트 데이터가 복잡하지 않다면 SQL 의 Procedure 를 사용하여 더미 데이터를 쉽게 만들 수 있습니다. 항상 INSERT 문을 복사하거나 Mockaroo 에서 테스트 데이터를 가져왔었는데, 새로운 방법을 알게되어 기분이 매우 좋습니다.