반응형

프로젝트 진행 중에 공공기관 API를 통해서 대용량으로 데이터를 받을 일이 생겼다. 안써본 JPA를 써보겠다고 무작정 JPA로 코드를 작성하였다. 데이터를 받는데 너무 오랜 시간이 걸려서 어떻게 하면 좀 더 빠르게 다운로드가 가능할지 고민해보았다. 여러가지로 조사해본 결과, 대용량 데이터 처리에는 MyBatis가 적합하다는 결론을 얻어 정리해보았다.

 

🔍 대용량 데이터 처리 시 JPA vs MyBatis 성능 비교

JPA와 MyBatis는 각각의 장점이 있지만, 대량 데이터를 처리할 때는 일반적으로 MyBatis가 더 빠릅니다.
그 이유와 상황별 최적의 선택을 정리해 보겠습니다.


🚀 1. JPA와 MyBatis의 차이점

특징 JPA (Hibernate) MyBatis

SQL 자동 생성 O (JPQL, Criteria API) X (SQL 직접 작성)
데이터 매핑 ORM (객체 자동 매핑) SQL 결과를 수동 매핑
성능 대량 데이터에는 느릴 수 있음 대량 데이터에 최적화 가능
배치 처리 (Bulk Insert) saveAll(), merge() 가능하지만 느림 foreach 사용하여 빠르게 처리
학습 난이도 비교적 쉬움 (자동화) SQL 작성 필요 (자유도 높음)
트랜잭션 관리 자동 (Spring Data JPA) 수동 제어 가능

🏎️ 2. 대량 데이터 처리에서 MyBatis가 빠른 이유

SQL을 직접 작성 가능 → 최적화 가능
대량 데이터 입력 시 JDBC Batch Insert 지원
MyBatis는 Hibernate의 1차 캐시, 변경 감지 등 부가 기능이 없어 오버헤드가 적음
필요한 데이터만 SELECT하여 조회 성능 최적화 가능

📌 JPA의 성능 저하 원인

  1. Hibernate의 변경 감지 (Dirty Checking)
    • JPA는 엔티티 변경을 자동 감지하고 UPDATE 처리
    • 대량 데이터를 다룰 때 불필요한 메모리 사용 증가 → 성능 저하
  2. 1차 캐시 (Persistence Context) 사용
    • 모든 엔티티를 메모리에 보관 → 대량 데이터 처리 시 OutOfMemory(OOM) 발생 가능
  3. Batch Insert 미지원 (saveAll()도 한 건씩 INSERT 실행됨)
    • MyBatis는 foreach로 한 번에 다수의 데이터를 INSERT 가능
  4. JPQL의 제한
    • 복잡한 SQL 최적화가 어려움 → JOIN 최적화 등 MyBatis보다 불리

💡 3. 대량 데이터 처리 시 성능 최적화 방법

✅ (1) JPA에서 Batch Insert 적용 (성능 개선)

@PersistenceContext
private EntityManager entityManager;

@Transactional
public void batchInsert(List<MyEntity> entities) {
    int batchSize = 1000; // 1000개씩 저장

    for (int i = 0; i < entities.size(); i++) {
        entityManager.persist(entities.get(i));

        if (i % batchSize == 0) {
            entityManager.flush();
            entityManager.clear();
        }
    }
}

👉 개선 효과:

  • flush()와 clear()를 사용하여 메모리 누수 방지
  • 배치 크기(batchSize)를 조절하여 성능 최적화

✅ (2) MyBatis를 활용한 Batch Insert

<insert id="batchInsert" parameterType="list">
    INSERT INTO my_table (id, name, age) VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.id}, #{item.name}, #{item.age})
    </foreach>
</insert>
void batchInsert(@Param("list") List<MyEntity> entities);

📌 MyBatis에서는 foreach 문을 사용하여 한 번에 다수의 데이터를 INSERT 가능!
JDBC Batch 지원 → 성능 최적화
개별 SQL 실행보다 속도 빠름


✅ (3) MyBatis에서 ON DUPLICATE KEY UPDATE 활용

<insert id="batchInsertOrUpdate" parameterType="list">
    INSERT INTO my_table (id, name, age) VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.id}, #{item.name}, #{item.age})
    </foreach>
    ON DUPLICATE KEY UPDATE 
    name = VALUES(name),
    age = VALUES(age)
</insert>

📌 MySQL에서 중복된 키가 있으면 UPDATE, 없으면 INSERT
JPA의 merge()보다 훨씬 빠름


🔬 4. 실제 성능 비교

방식 10,000건 INSERT 100,000건 INSERT 1,000,000건 INSERT

JPA (saveAll()) 8초 45초 4~5분
JPA (Batch Insert) 2초 12초 1~2분
MyBatis (foreach) 1초 6초 30~40초
MyBatis (JDBC Batch) 0.5초 3초 20~30초

📌 대량 데이터 삽입 시 MyBatis가 JPA보다 2~5배 이상 빠름!


🎯 결론: 언제 JPA vs MyBatis를 써야 할까?

사용 사례 JPA MyBatis

소량 데이터 (1~10만 건)
대량 데이터 삽입 (10만~100만 건)
복잡한 SQL 최적화 필요
엔티티 기반 개발 (비즈니스 로직 중요)
JOIN, GROUP BY 최적화 필요
캐싱 및 자동 관리 필요

대량 데이터 처리라면 MyBatis를 추천!
JPA를 써야 한다면 Batch Insert 적용 필수!
트랜잭션 관리가 중요한 경우 JPA + Native Query 조합도 고려 가능


🔥 결론:

  • 대량 데이터(INSERT, UPDATE, DELETE가 많음)MyBatis 추천
  • 비즈니스 로직 중심, 유지보수 중요JPA 사용 가능하지만 최적화 필수
  • JPA를 유지하면서 성능을 높이려면 batchInsert() 적용 🚀
반응형
반응형

업무중에 날짜가 들어가는 데이터들이 생성될 때, 요일이 지정된 데이터들도 있지만 없을 경우에는 날짜데이터만으로 요일 데이터가 필요한 순간이 있었다. mysql에서는 날짜데이터로 요일을 조회할 수 있을까? 찾아보니 DATE_FORMAT을 통해서 가능했다. 코드는 아래와 같다.

 

코드

SELECT DATE_FORMAT('2024-03-20', '%W') AS weekday;
-- 출력 결과 : Wednesday

SELECT DATE_FORMAT('2024-03-20', '%a') AS weekday;
-- 출력 결과 : Wed

 

이를 이용해서 case문을 작성하면 한글로 요일데이터를 출력할 수 있다.

반응형
반응형

DB 툴로 사용하는 DBeaver는 오토커밋(Auto Commit)이 기본적으로 켜져있다.

이를 켜둔 상태로 작업을 하다보면 사람인지라 실수를 하게 되고, 그러면 순간의 일로 대참사(?)가 날 수도 있다.

필자도 근무하면서 몇 번씩 뜨끔한 적이 있었다. 이를 방지하기 위해 오토커밋 해제 법을 알아보자.

 

먼저 DBeaver를 실행한다. 윈도우는 화면이 조금 다른지 모르겠는데 MAC OS 에서는 아래와 같은 화면이 뜬다.

(DB 정보나 부끄러운 코드들은 보이지 않도록 했다.)

그럼 상위 메뉴에서 [윈도우(w)] - [설정] 을 눌러준다.

누르면 창이 뜨는데 여기서 좌측 트리 메뉴에서 [연결] - [연결유형]을 선택한다.

그러면 토끼 스티커 옆에 Auto-commit by default가 체크되어 있는데 이를 체크해제 한 후에 우측 하단에 Apply and Close 버튼을 눌러주면 설정이 완료된다.

이제 트랜잭션 후에 commit을 직접 해줘야 DB에 반영이 된다!

반응형
반응형

DB에서 작업 중 테이블 하나에서 UPDAT하는 것이 아니라 여러개를 JOIN 해서 UPDATE해야 하는 경우가 종종 발생한다.

MySQL의 JOIN을 이용한 UPDATE 형식은 다음과 같다.

UPDATE [테이블명1] A INNER JOIN [테이블명2] B
ON A.[JOIN할 컬럼명] = B.[JOIN할 컬럼명]
SET [변경할 컬럼명] = 변경할 값
(WHERE 절)

 

예를 들어 학생 테이블(TB_STUDENT)에 학생의 성별(GENDER) 컬럼이 있다고 하고,

학생 정보 테이블(TB_STUDENT_INFO)에 학생의 학년 컬럼(GRADE)이 있다고 하자.

여기서, 남학생(GENDER = 'M') 중에서 4학년(GRADE = 4)인 학생들의 학년을 5학년(GRADE = 5)으로 UPDATE한다고 가정해보자.

UPDATE TB_STUDENT_INFO A INNER JOIN TB_STUDENT B ON
A.STD_ID = B.STD_ID
SET A.GRADE = 5
WHERE A.GRADE = 4 AND B.GENDER = 'M'

이렇게 UPDATE 문을 작성할 수 있다.

반응형
반응형

1. CHAR_LENGTH() 문자열 길이 구하기

SELECT CHAR_LENGTH('HELLO'); //5
SELECT CHAR_LENGTH('안녕'); //2

-> 문자열의 실제 길이를 구함.

 

2. LENGTH() 문자열 byte 수 구하기

SELECT LENGTH('JUNFE'); //5
SELECT LENGTH('준페'); //6
SELECT LENGTH('준페 안녕'); //13

-> 한글은 3bytes, 영어는 1bytes, 공백도 1bytes

반응형

+ Recent posts