테스트 데이터 삽입 ‐ (2) 회원 데이터 삽입 - ttasjwi/board-system GitHub Wiki

회원 테이블 생성

use board_db_test;
drop table users;
create table if not exists users(
    user_id       BIGINT       NOT NULL,
    email         VARCHAR(255) NOT NULL,
    password      VARCHAR(68)  NOT NULL,
    username      VARCHAR(15)  NOT NULL,
    nickname      VARCHAR(15)  NOT NULL,
    role          VARCHAR(10)  NOT NULL,
    registered_at DATETIME     NOT NULL
);
  • 일부러 제약조건 없이 데이터 생성

csv 파일 생성

package com.ttasjwi.board.system.app.user.data

import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import java.io.File
import java.time.format.DateTimeFormatter

class UserDataInitializer {

    @Test
    @DisplayName("회원 벌크 삽입 csv 파일 생성")
    fun initialize() {
        val csvFile = File("users.csv")
        val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
        csvFile.bufferedWriter().use { writer ->
            for (id in 1L..12_000_000L) {
                val paddedId = id.toString().padStart(8, '0')

                val email = "user${paddedId}@gmail.com"
                val password = "{bcrypt}$2a$10\$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy"
                val username = "user${paddedId}"
                val nickname = "user${paddedId}"
                val role = "USER"
                val registeredAt = java.time.LocalDateTime.now().format(formatter)
                writer.write("$id,$email,$password,$username,$nickname,$role,$registeredAt\n")

                if (id % 100000 == 0L) {
                    println("Written $id lines...")
                }
            }
        }
    }
}

}
  • 이 방식을 통해 csv 파일을 생성할 수 있다.
  • 테스트 편의를 위해 snowflake 알고리즘에 의해 생성하지 않고 숫자 id로 생성한다.
  • csv 파일을 통해 데이터를 생성하는 이유?
    • 트랜잭션 오버헤드 최소화
      • 애플리케이션에서 직접 DB에 하나씩 INSERT를 수행하면 건당 트랜잭션이 발생하거나,
      • 배치 처리하더라도 네트워크 I/O, DB 커넥션 횟수, 커밋 횟수가 많아짐.
      • 반면, CSV를 생성해서 LOAD DATA INFILE 등의 방식으로 한 번에 삽입하면:
        • 한 트랜잭션 또는 소수의 트랜잭션으로 처리 가능
        • 성능이 수십 배 이상 향상되는 경우도 있음
    • 네트워크 I/O 비용 감소
      • 애플리케이션 → DB로 INSERT를 반복하면 빈번한 네트워크 왕복이 발생한다.
      • 로컬 파일을 서버에 복사해두고 MySQL 서버 내부에서 읽으면 I/O 비용이 훨씬 적음
    • MySQL 의 대량 삽입 최적화 지원
      • MySQL은 LOAD DATA INFILE, LOAD DATA LOCAL INFILE, BULK INSERT 등의 대량 삽입 메커니즘을 제공
      • CSV 형식은 그중 가장 직관적이고 지원이 넓은 표준 포맷이므로, 대량 삽입 시 효율적
    • 데이터 생성과 삽입 분리
      • CSV로 생성해두면 데이터 생성 로직과 DB 삽입을 분리할 수 있어 유지보수성과 재사용성이 높아짐
      • 예: 성능테스트에서 여러번 재삽입하거나, DB 초기화 등에 재활용 가능
      • 예: 일단 로컬에서 데이터를 생성하여 테스트 해보고, 나중에 테스트 서버에 데이터 삽입시에도 CSV 파일 재사용 가능

데이터 삽입 (로컬)

docker cp data/users.csv mysql:/tmp/users.csv
LOAD DATA INFILE '/tmp/users.csv'
INTO TABLE users
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
(user_id, email, password, username, nickname, role, registered_at);

데이터삽입 (RDS)

  • datagrip 을 통해 편리하게 가능.

image

  • 접속설정

image

  • advanced -> allowLoadLocalInfile 허용

회원 조회

mysql> select count(*) from users;
+----------+
| count(*) |
+----------+
| 12000000 |
+----------+
1 row in set (3.47 sec)

mysql> select * from users order by user_id asc limit 30;
+---------+------------------------+----------------------------------------------------------------------+--------------+--------------+------+---------------------+
| user_id | email                  | password                                                             | username     | nickname     | role | registered_at       |
+---------+------------------------+----------------------------------------------------------------------+--------------+--------------+------+---------------------+
|       1 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000001 | user00000001 | USER | 2025-06-09 14:39:08 |
|       2 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000002 | user00000002 | USER | 2025-06-09 14:39:08 |
|       3 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000003 | user00000003 | USER | 2025-06-09 14:39:08 |
|       4 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000004 | user00000004 | USER | 2025-06-09 14:39:08 |
|       5 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000005 | user00000005 | USER | 2025-06-09 14:39:08 |
|       6 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000006 | user00000006 | USER | 2025-06-09 14:39:08 |
|       7 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000007 | user00000007 | USER | 2025-06-09 14:39:08 |
|       8 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000008 | user00000008 | USER | 2025-06-09 14:39:08 |
|       9 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000009 | user00000009 | USER | 2025-06-09 14:39:08 |
|      10 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000010 | user00000010 | USER | 2025-06-09 14:39:08 |
|      11 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000011 | user00000011 | USER | 2025-06-09 14:39:08 |
|      12 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000012 | user00000012 | USER | 2025-06-09 14:39:08 |
|      13 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000013 | user00000013 | USER | 2025-06-09 14:39:08 |
|      14 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000014 | user00000014 | USER | 2025-06-09 14:39:08 |
|      15 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000015 | user00000015 | USER | 2025-06-09 14:39:08 |
|      16 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000016 | user00000016 | USER | 2025-06-09 14:39:08 |
|      17 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000017 | user00000017 | USER | 2025-06-09 14:39:08 |
|      18 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000018 | user00000018 | USER | 2025-06-09 14:39:08 |
|      19 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000019 | user00000019 | USER | 2025-06-09 14:39:08 |
|      20 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000020 | user00000020 | USER | 2025-06-09 14:39:08 |
|      21 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000021 | user00000021 | USER | 2025-06-09 14:39:08 |
|      22 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000022 | user00000022 | USER | 2025-06-09 14:39:08 |
|      23 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000023 | user00000023 | USER | 2025-06-09 14:39:08 |
|      24 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000024 | user00000024 | USER | 2025-06-09 14:39:08 |
|      25 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000025 | user00000025 | USER | 2025-06-09 14:39:08 |
|      26 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000026 | user00000026 | USER | 2025-06-09 14:39:08 |
|      27 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000027 | user00000027 | USER | 2025-06-09 14:39:08 |
|      28 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000028 | user00000028 | USER | 2025-06-09 14:39:08 |
|      29 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000029 | user00000029 | USER | 2025-06-09 14:39:08 |
|      30 | [email protected] | {bcrypt}$2a$10$glxdATzDUUpvB92yt7OkI.zCPjgn1R1v2uWnQ43gHo.st2t9B9hMy | user00000030 | user00000030 | USER | 2025-06-09 14:39:08 |
+---------+------------------------+----------------------------------------------------------------------+--------------+--------------+------+---------------------+


  • 회원 데이터가 잘 삽입된 것 같다.

회원테이블에 제약조건 추가

ALTER TABLE users
ADD CONSTRAINT unique_email UNIQUE (email),
ADD CONSTRAINT unique_username UNIQUE (username),
ADD CONSTRAINT unique_nickname UNIQUE (nickname);

DATA GRIP 에 맞게 생성

  • 테이블을 생성하고 테이블에 우클릭해서 csv 파일을 import 할 수 있다.