MySQL ‐ INSERT - thought-corner/Backend-PlayGround GitHub Wiki

MySQL - INSERT

다중 행 삽입 (Bulk Insert) - 네트워크 및 I/O 최적화

  • 여러 건의 데이터를 하나의 쿼리로 묶어서 보내는 것을 말한다.
  • DB 서버와 통신할 때 가장 큰 비용을 차지하는 것은 데이터 자체가 아니라 네트워크 왕복(Round-Trip)과 DB 내부의 쿼리 파싱 및 트랜잭션 커밋 비용이다.
  • 1,000건의 데이터를 1,000번의 쿼리로 쪼개서 보내면 이 비용이 1,000배로 발생하지만, Bulk Insert를 사용하면 단 1번으로 줄일 수 있다.
-- 100건의 데이터를 1번의 쿼리로 묶어서 실행 (속도 수십~수백 배 향상)
INSERT INTO stock_trade_history (stock_code, trade_date, closing_price) 
VALUES 
    ('005930', '2026-04-12', 80000),
    ('000660', '2026-04-12', 150000),
    ('035420', '2026-04-12', 200000);
  • 인덱스 재정렬(B-Tree 갱신)도 데이터를 한꺼번에 모아서 처리하므로 디스크 쓰기 속도가 훨씬 빠르다.

병합 삽입 (Upsert) - 비즈니스 로직 최적화

  • 데이터를 수집하다 보면 이미 DB에 존재하는 데이터면 수정(Update)하고, 없으면 삽입(Insert)하라는 로직이 자주 필요하다.
  • 애플리케이션 코드에서 이 로직을 처리하면 SELECT로 확인 후 INSERT 또는 UPDATE를 실행해야 하므로 통신이 2배로 발생하고, 동시성 문제(Race Condition)까지 겪게 되는데 이를 DB 레벨에서 원자적(Atomic)으로 한 번에 처리하는 기법이 바로 Upsert이다.
-- 테이블에 (stock_code, trade_date) 조합으로 UNIQUE 인덱스가 걸려있다고 가정
INSERT INTO stock_trade_history (stock_code, trade_date, closing_price, trade_volume)
VALUES ('005930', '2026-04-12', 81000, 5000000)
ON DUPLICATE KEY UPDATE 
    closing_price = VALUES(closing_price), -- 새롭게 들어온 81000으로 덮어씀
    trade_volume = trade_volume + VALUES(trade_volume); -- 기존 누적 거래량에 방금 수집한 거래량을 더함
INSERT IGNORE INTO stock_trade_history (stock_code, trade_date, closing_price)
VALUES ('005930', '2026-04-12', 80000);