빅데이터 및 DB/MySQL

[MySQL] Batch 및 Load 비교.

Steve Jang 2018. 8. 20. 10:32

MySQL에서 대용량의 데이터 처리를 하기 위해서 주로 쓰이는 두개의 방식인 Batch와 Load 방식에 대한 장단점을 비교하기로 한다. 어느 것이 무조건 좋다 나쁘다를 할 수 없기 때문에 어떤 상황에서 이 방식을 써야 할지 등을 알려보고자 한다.


참고로, 필자가 다니는 회사는 전국민 상대로 서비스를 하고 있으며, 하루에도 몇십만명 이상이 사이트를 방문하기에 당연히 몇백만 이상의 로그가 쌓이고 있다. 데이터 분석을 한 결과(몇천만건 ~ 억단위)를 DB에 매일 배치 형태로 밀어 넣고 있는데 몇백에서 몇기가 단위의 데이터를 DB에 밀어 넣을 때는 늘 상 load(부하)를 잘 관리해야만 할 것이다.




Batch 방식


일단, 많이들 알고 있는 Batch 방식은 Insert를 Add 시킨 후, 한번에 커밋(commit) 하는 방식이다. 이 방식의 장점은 데이터를 핸들링 하기 편하다는 장점이 있다. 보통 데이터를 DB에 로드를 한다는 것은 꽤나 큰 부하이며, 부하가 가지 않는 선 내에서 적절하게 DB에 밀어 넣을 수 있는 장점이 있는데 서비스를 하는 DB에 무리가 간다면 load보다 Batch를 하는 방법이 좋을 것이다.


소스예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// prepared로 처리
Connection conn = null;
PreparedStatement pstmt = null;
int rc = 0;
 
String sql = "조회쿼리";
 
try {
    conn = getConnection();
    pstmt = conn.prepareStatement(query);
    conn.setAutoCommit(false);
    
    for(DicWrdClsVO vo : list) {
        pstmt.setString(1, vo.getTitle);
        pstmt.setString(2, vo.getWrdCls());
        pstmt.setString(3, vo.getSynm());
        pstmt.setString(4, vo.getRegUser());
        
        pstmt.addBatch();
        rc++;
    }
    
    pstmt.executeBatch();
    conn.setAutoCommit(true);
    pstmt.clearBatch();
    
} catch (Exception e) {
    LOGGER.error("loadDic : " + e.getMessage());
    rc = -1;
} finally {
    if (pstmt != null) {
        pstmt.close();
    }
 
    if (conn != null) {
        conn.close();
    }
}
cs



Batch를 할 때는, iBatis 혹은 MyBatis같은 프레임워크를 사용하는 것보다 이렇게 Java Sample 소스처럼 코딩한 것을 넣는 것이 훨씬 편하고 빠르다. 예전에 iBatis로 배치 작업을 한 적이 있었지만, 속도면에서 차이가 심했었음.



대용량일 경우, 위 방식에서 for문을 넣은 후, 10만건마다 setAutoCommit(true)등을 넣어주는 방식으로 처리를 해야 부하에 대한 핸들링이 원활할 것이다.



Load 명령어


MySQL에는 LOAD DATA라는 명령어를 지원하고 있는데 csv를 DB에 전송하는 것이다. 이 명령어를 자바로 코딩하여 DB에 직접 밀어넣을 경우, 첫번째 방식인 Batch 작업보다 월등히 빠른 속도를 느낄 수 있을 것이다. 다만 이렇게 할 경우, 대용량의 csv를 밀어 넣을 때, 부하에 대한 컨트롤이 힘든데 이럴 경우 csv를 잘게 쪼개서 넣으면 DB부하를 최소화 할 수 있다.


소스예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Connection conn = null;
PreparedStatement pstmt = null;
 
String filename = trinityVO.getServicePath() + "/" + fileNm;
 
String sql = "LOAD DATA LOCAL INFILE \"" + filename + "\" INTO TABLE "
        + tableNm + " FIELDS TERMINATED BY \',\'" + fields;
 
try {
    logger.info("load ... begin");
    
    conn = getDBConnection();
    pstmt = conn.prepareStatement(sql);
    
    conn.setAutoCommit(false);
    pstmt.executeUpdate();
    conn.setAutoCommit(true);
    
    pstmt.close();
    conn.close();
    
    logger.info("load...end");
} catch (Exception e) {
    e.printStackTrace();
    return false;
}
cs