|
| 1 | +--- |
| 2 | +layout: "post" |
| 3 | +title: "[MySQL] LOAD DATA로 대용량 데이터 빠르게 삽입하기" |
| 4 | +description: |
| 5 | + "MySQL의 `LOAD DATA` 명령어를 활용해 대용량 데이터를 빠르게 삽입하는 방법을 소개합니다. |
| 6 | + \ 이 명령어는 텍스트 파일에서 데이터를 읽어와 테이블에 신속하게 삽입하며, 일반적인 `INSERT`보다 약 20배 빠른 성능을 제공합니다. |
| 7 | + \ Container를 사용해 MySQL 환경을 설정하고, CSV 파일을 통해 데이터를 삽입하는 과정을 설명합니다. |
| 8 | + \ 이를 통해 대량의 데이터를 효율적으로 처리할 수 있음을 확인했습니다." |
| 9 | +categories: |
| 10 | + - "스터디-데이터베이스" |
| 11 | + - "개발" |
| 12 | +tags: |
| 13 | + - "MySQL" |
| 14 | + - "LOAD DATA" |
| 15 | + - "대용량" |
| 16 | + - "INSERT" |
| 17 | + - "BULK INSERT" |
| 18 | + - "BULK" |
| 19 | + - "Podman" |
| 20 | + - "Docker" |
| 21 | + - "Container" |
| 22 | + - "Thread" |
| 23 | + - "Single Thread" |
| 24 | +date: "2025-07-16 14:00:00 +0000" |
| 25 | +toc: true |
| 26 | +image: |
| 27 | + path: "/assets/thumbnails/2025-07-16-mysql-load-data.jpg" |
| 28 | +--- |
| 29 | + |
| 30 | +# `LOAD DATA` 로 대용량 데이터 빠르게 삽입하기 |
| 31 | + |
| 32 | +작년 말에 K-DEVCON 스터디에서 MySQL을 공부하면서 `LOAD DATA` 명령어에 대해서 알게 되었다. |
| 33 | + |
| 34 | +- [INSERT, UPDATE, DELETE 쿼리 작성 및 최적화 - Real MySQL 스터디 7회차](https://jonghoonpark.com/2024/12/21/mysql-insert-update-delete-optimize) |
| 35 | + |
| 36 | +최근 대용량 테스트 데이터를 적재해야 하는 상황이 생기면서, `LOAD DATA` 를 실제로 사용해볼 기회가 생겼다. |
| 37 | + |
| 38 | +## LOAD DATA 란? |
| 39 | + |
| 40 | +[LOAD DATA](https://dev.mysql.com/doc/refman/8.4/en/load-data.html) 명령어는 텍스트 파일로부터 데이터를 읽어와 테이블에 매우 빠르게 삽입할 수 있다. Real MySQL에서는 그냥 insert 하는 것과 비교하면 약 20배의 성능차를 보여준다고 설명이 나와있다. |
| 41 | + |
| 42 | +`LOAD DATA` 는 빠르지만, **단일 스레드** 로 동작한다는 점에 유의하여 사용한다. Real MySQL에서는 여러개의 파일로 분할하여 병렬로 진행하라는 팁을 제공해주었다. |
| 43 | + |
| 44 | +## LOAD DATA 사용해보기 |
| 45 | + |
| 46 | +### MySQL 세팅 |
| 47 | + |
| 48 | +**Docker Desktop** 을 사용하지 못하는 환경이라, **Podman Desktop** 을 사용하였다. [**Podman**](https://podman.io/) 은 이번에 처음 사용해 보았는데 Docker 와 호환되는(Compatible) 한 인터페이스를 제공하여, Docker 경험이 있다면 큰 어려움 없이 사용할 수 있었다. |
| 49 | + |
| 50 | +실제 운영 환경과 동일하게 맞추기 위해 `MySQL 8.0.32` 버전으로 테스트를 진행하였다. |
| 51 | + |
| 52 | +```sh |
| 53 | +podman run -dit -e MYSQL_ROOT_PASSWORD=testtesttesttest -e MYSQL_DATABASE=test -p 3306:3306 --name local-mysql mysql:8.0.32 |
| 54 | +``` |
| 55 | + |
| 56 | +### 데이터 세팅 |
| 57 | + |
| 58 | +간단한 자바코드를 작성하여 파일로 csv 파일을 생성하도록 하였다. 컬럼 헤더는 csv에 담지 않았다. [faker](https://github.com/DiUS/java-faker) 를 이용하여 어느 정도 랜덤한 있는 데이터가 나올 수 있도록 하였다. 테스트 데이터도 최대한 실제와 유사하기 위해 암호화도 적용하여 데이터를 생성하게 하였다. |
| 59 | + |
| 60 | +``` |
| 61 | +USER0000001,7426C09FB3...,Rob,Gerlach,47a7e9bd9...,251FE112...,10,\N,10,\N,\N,N,0,40,... |
| 62 | +... |
| 63 | +``` |
| 64 | + |
| 65 | +csv 특성 상 `null` 처리가 까다로운데, `LOAD DATA` 는 `\N` 을 `null`로 인식한다. |
| 66 | + |
| 67 | +그냥 빈 공백으로 처리할 경우 삽입 처리중에 아래와 같은 에러가 발생될 수 있으니 주의하자. |
| 68 | + |
| 69 | +``` |
| 70 | +[22001][1292] Data truncation: Incorrect ... value: '' for column 'column_name' at row xxx |
| 71 | +``` |
| 72 | + |
| 73 | +### Data 파일을 container 내부로 복사하기 |
| 74 | + |
| 75 | +다음과 같이 cp 명령어를 사용하여 데이터 파일을 container 내부로 복사할 수 있다. |
| 76 | + |
| 77 | +```sh |
| 78 | +podman cp /Users/jonghoonpark/project/slow-query-select-member-list/output.csv local-mysql:/var/lib/mysql-files/file.csv |
| 79 | +``` |
| 80 | + |
| 81 | +### LOAD DATA 를 이용하여 데이터 삽입 |
| 82 | + |
| 83 | +파일을 컨테이너 내부로 옮겼다면, 아래 명령어를 통해 데이터를 삽입할 수 있다. `USER_TABLE` 이라는 이름의 테이블에 데이터를 삽입한다. |
| 84 | + |
| 85 | +```SQL |
| 86 | +LOAD DATA INFILE '/var/lib/mysql-files/file.csv' |
| 87 | +INTO TABLE USER_TABLE |
| 88 | +FIELDS TERMINATED BY ',' -- csv 파일의 구분자 (쉼표인 경우) |
| 89 | +ENCLOSED BY '"' -- 필드가 따옴표로 묶여 있는 경우 |
| 90 | +LINES TERMINATED BY '\n' -- 줄 바꿈 문자 (Unix/Linux 기준) |
| 91 | +-- IGNORE 1 LINES; -- 헤더 있는 경우 |
| 92 | +``` |
| 93 | + |
| 94 | +### 테스트 1 : INSERT 와 LOAD DATA 간의 소요시간 비교 (작성중) |
| 95 | + |
| 96 | +실행 환경은 다음과 같다. |
| 97 | + |
| 98 | +- 데이터는 **400만개** 로 고정 |
| 99 | +- `vCPU 16`, `메모리 16GB` 할당으로 고정 |
| 100 | +- 실행을 마친 후에는 table 을 truncate 한 후, container를 재실행 |
| 101 | + |
| 102 | +| 방식 | 소요시간 | |
| 103 | +| --------- | -------- | |
| 104 | +| INSERT | | |
| 105 | +| LOAD DATA | | |
| 106 | + |
| 107 | +결과 : |
| 108 | + |
| 109 | +### 테스트 2 : vCPU 할당에 따른 소요시간 비교 (작성중) |
| 110 | + |
| 111 | +실행 환경은 다음과 같다. |
| 112 | + |
| 113 | +- 데이터는 **400만개** 로 고정 |
| 114 | +- `메모리 16GB` 할당으로 고정 |
| 115 | +- 실행을 마친 후에는 table 을 truncate 한 후, container를 재실행 |
| 116 | + |
| 117 | +| Podman vCPU 할당 | 소요시간 | |
| 118 | +| ---------------- | -------- | |
| 119 | +| vCPU 2 | | |
| 120 | +| vCPU 4 | | |
| 121 | +| vCPU 8 | | |
| 122 | +| vCPU 16 | | |
| 123 | + |
| 124 | +결과 : |
| 125 | + |
| 126 | +## 마무리 (작성중) |
| 127 | + |
| 128 | +스터디를 하며 배웠던 `LOAD DATA` 를 실제로 사용해보고, 대용량 데이터를 빠르게 삽입할 때 매우 효과적인 방법임을 확인할 수 있었다. |
0 commit comments