Note7 [Note] MySQL utf8mb4_unicode_ci 들어가기 전공급사로부터 받은 이미지 caption을 내부 카테고리로 매핑하는 배치가 있다. 구조는 단순하다. 미리 적재해 둔 매핑 테이블을 부트스트랩 시점에 캐시로 올려두고, 런타임에 caption을 정규화(canonicalize)한 뒤 캐시에서 조회하는 것이다. 그런데 어느 날, 분명히 매핑 데이터를 넣어 뒀는데도 특정 caption이 계속 UNMATCHED로 처리됐다. SQL 파일에도 있고, 미매핑 추적용 CSV에도 있었다. DB 부트스트랩은 항상 실행되는 always 모드였다. 로그만 보면 완벽하게 정상이었다. 처음엔 배치 코드 쪽을 의심했다. SQL 파일이 제대로 실행됐는지, 캐시 로딩에 타이밍 문제가 있는 건 아닌지, canonical key 생성 과정에서 뭔가 빠지는 건 아닌지. 코드를 훑어봐.. 2026. 4. 26. [Note] ItemReader를 어떻게 구현해야할까 Spring Batch로 대용량 배치를 작성하다 보면 ItemReader를 직접 구현해야 하는 상황이 생긴다. 특히 cursor 기반 페이징을 직접 제어해야 할 때, 자연스럽게 두 가지 구현 방향 중 하나를 선택하게 된다.이 글은 그 두 방향을 비교하고, 왜 구조적 명확성 측면에서 하나의 방식이 더 나은지 정리한 내용이다.배경: cursor 기반 페이징이 필요한 이유대용량 배치에서 offset 기반 페이징은 잘 알려진 함정이 있다.SELECT * FROM property ORDER BY id LIMIT 500 OFFSET 100000-- offset이 커질수록 앞의 100000건을 매번 스캔 → 후반부로 갈수록 느려짐이를 피하기 위해 lastId를 커서로 사용하는 방식을 쓴다.SELECT * FROM p.. 2026. 4. 19. [Note] Elasticsearch ID 필드 타입 설계 사내에서 제공하는 검색 SDK를 통해 Elasticsearch 기반 숙소 검색 시스템을 구성하고 있었다. regionId, poiId, categoryId, roomViewIds 같은 필드들은 SDK가 제공하는 NumberField 타입으로 정의되어 있었고, 나는 이 이름을 보고 별다른 의심 없이 사용했다. 숫자 값을 저장하는 필드이니 NumberField가 당연히 맞는 선택이겠거니 했다. 이 필드들이 어떤 ES 타입으로 실제 매핑되는지, 그 타입이 내부적으로 어떤 자료구조를 쓰는지는 생각하지 않았다.의문이 생긴 건 외부 기술 블로그를 읽다가였다. Elasticsearch에서 숫자 타입과 keyword 타입이 내부적으로 전혀 다른 자료구조를 사용하며, 쿼리 패턴에 따라 그 선택이 성능에 의미 있는 차이를.. 2026. 4. 15. [Note] MySQL MATERIALIZED 전략 이해하기 들어가기 전개발 환경의 이미지 테이블에 약 1억 건이 적재되어 있는 상황에서 배치 애플리케이션을 테스트하던 중, 실수로 중복 프로퍼티가 약 10만 건 적재됐다. 인덱스는 충분히 구성되어 있었고, 삭제 대상만 별도로 관리하기 위해 임시 테이블(tmp_delete_provider_property_ids)도 미리 준비해 둔 상태였다.처음 실행한 쿼리는 다중 테이블 DELETE였다. delete afrom tb_provider_property_image ajoin tmp_delete_provider_property_ids t on t.provider_property_id = a.provider_property_idwhere a.provider_id = 2; JOIN 방식의 DELETE는 실행 계획상 N.. 2026. 3. 30. [Note] 혼합 워크로드 환경에서의 처리 전략 들어가기 전배치 애플리케이션을 설계할 때 흔히 저지르는 첫 번째 오류는, 모든 작업을 하나의 성격으로 간주하는 것이다. 실제 운영 환경에서의 배치는 대개 순수한 I/O 바운드도 아니고 순수한 CPU 바운드도 아니다. 두 특성이 단계적으로, 혹은 동시에 교차한다. 문제는 이 혼합 상태를 단일 실행 모델로 처리하려 할 때 발생한다. 예를 들어 Reader는 DB에서 이미지 메타데이터를 조회하고, Processor는 외부 HTTP API를 호출하여 이미지를 분석한 뒤, 추가적으로 로컬에서 feature 계산을 수행하며, Writer는 결과를 upsert한다. 이 구조는 전형적인 혼합 워크로드다. HTTP 호출은 I/O Burst이고, feature 계산은 CPU Burst다. Writer는 다시 JDBC ba.. 2026. 2. 24. [Note] 성능 개선 전략: 인덱스, 역정규화 들어가기 전성능 개선을 이야기할 때 가장 흔하게 등장하는 단어는 인덱스다.쿼리가 느리면 인덱스를 추가하고 그래도 느리면 인덱스를 하나 더 추가한다.하지만 실무에서는 인덱스를 아무리 추가해도 성능이 거의 개선되지 않는 경우가 분명히 있을 뿐더러 오히려 무분별한 인덱스 추가는 쓰기 성능 저하, 저장 공간 증가, 인덱스 유지·관리 비용 상승 같은 부작용을 낳을 수 있다.이 글은 그런 상황에서 출발한다.호텔을 검색할 때 전형적인 읽기 중심 도메인을 기준으로 정규화된 모델이 왜 느려지는지 그 문제를 해결하기 위해 왜 역정규화를 먼저 선택하게 되는지 그 이후 인덱스와 비트맵 설계가 어떤 역할을 맡게 되는지를 순서대로 정리한다.핵심은 "어떤 기법이 빠르다"가 아니라 "어떤 문제에 어떤 순서로 접근해야 하는가" 다.1.. 2026. 2. 2. [Note] 대량 Delete 작업 중 발생한 lock 문제 분석 1.문제 상황Spring Batch 기반의 백엔드 시스템에서 멀티 스레드로 대용량 삭제 작업을 수행하는 중 지속적으로 락 대기 시간 초과(Lock wait timeout) 이 발생하였습니다. 해당 배치 작업은 총 10개의 스레드가 병렬로 실행되며 대부분의 데이터를 미리 Processor 레벨에서 가공하여 삭제 -> insert 하는 방식으로 실행되었는데 예를 들어 tb_order_item 테이블에서 특정 order_id 목록에 해당하는 행들을 한꺼번에 삭제하는 형태였습니다.-- 예시: 하나의 스레드가 실행하는 삭제 쿼리 (IN 절에 다수의 ID 포함)deletefrom tb_order_itemwhere order_id in (101, 102, ..., 250);대게 그렇듯이 다른 테이블들도 유사한 패턴으.. 2026. 1. 6. 이전 1 다음