모든 글
총 21개의 글
-
입금자명으로 정산 자동화하기: difflib vs BM25
입금자명으로 거래처를 찾는 데 difflib와 BM25를 썼습니다. 실제 입금 1,460건에서 이름을 정규화하면 1위 정확도는 difflib 79.0%, BM25 79.8%로 비슷했습니다. BM25는 한 건에 0.45ms로 48배 빨랐고 1위 동점이 적었습니다. 두 방법이 점수를 매기는 방식의 차이는 가상 예시로 따라갑니다.
-
데이터베이스 정규화 (9): 정규화 절차와 역정규화, 나눈 뒤에 되돌리는 선택
1편부터 8편까지의 정규화를 한 절차로 모읍니다. 각 단계가 어떤 종속을 찾아 어떻게 나누는지, 어디서 멈추는지, 그리고 나눈 테이블에 중복을 다시 넣는 역정규화가 정규화하지 않은 상태와 무엇이 다른지를 MariaDB에서 확인한 갱신 이상과 함께 다룹니다.
-
VARCHAR를 255자 넘게 잡으면 느려질까?
컬럼 길이를 100자에서 1000자로 늘려 달라는 요청에 "255자를 넘기면 성능이 달라진다"는 말이 나왔습니다. MariaDB 11.4.2에서 재 보니 255는 글자가 아니라 바이트에 붙은 숫자였고, 실행 시간을 가르는 선은 메모리 임시 테이블이 감당하는 512자에 있었습니다.
-
데이터베이스 정규화 (8): 제4정규형과 제5정규형, 함수적 종속 너머의 중복
BCNF를 만족하는 테이블에도 중복이 남습니다. 함수적 종속으로는 설명되지 않는 그 중복의 이름인 다치 종속과 조인 종속, 자명한 종속을 조건에서 빼는 이유, 제4정규형과 제5정규형의 정의와 분해 절차, 그리고 도메인키 정규형과 제6정규형까지 정리합니다.
-
데이터베이스 정규화 (7): 자연키와 대리키, 무엇을 기본키로 삼을 것인가
자연키와 대리키(surrogate key)를 다룹니다. 용어의 출발과 Codd가 1979년에 지적한 자연키의 세 가지 문제, 두 방식의 장단점, JPA에서 자연키를 어디에 적어야 하는지, 그리고 자연키가 없으면 정규화를 못 한다는 오해까지 정리합니다.
-
collation이 뭐길래 조인만 실패할까?
이력 테이블을 코드 테이블과 조인하지 못해 데이터팀 작업이 막혔습니다. 원인은 collation 불일치였습니다. collation이 문자 집합과 무엇이 다른지, 왜 컬럼끼리 비교할 때만 Illegal mix of collations가 나는지, 그리고 한국어와 코드 값을 다루는 곳에서 utf8mb4_general_ci를 컨벤션으로 두면 무엇이 나은지 정리했습니다.
-
집계용 중간 결과 테이블을 Global Temporary Table로 바꾸기
집계 중간 결과를 일반 테이블 하나에 담고 매 실행 앞에서 DELETE로 비우면 비용이 세 군데서 나옵니다. Global Temporary Table이 그중 무엇을 없애고, redo 감소는 왜 조건부인지 Oracle 12c 문서를 근거로 정리합니다.
-
Spring과 Jackson에서 필드 부재와 명시적 null 구분하기
수정 API에서 필드에 null을 넣는 것과 필드를 아예 빼는 것은 다릅니다. 서버가 필드 부재와 명시적 null을 구분하지 못하면 null 규칙을 정할 수 없습니다. Jackson의 동작과 패치 본문 형식을 로컬에서 실행해 확인했습니다.
-
Claude Code에서 Kotlin LSP가 참조를 못 찾을 때: Gradle 프로젝트 루트 확인하기
Kotlin LSP 프로세스가 실행 중이어도 Gradle 프로젝트 루트가 틀리면 findReferences가 다른 파일의 사용처는 찾지 못하고 선언 위치만 반환할 수 있습니다. 서브디렉토리 프로젝트에서 원인을 구분하고 workspaceFolder로 교정하는 방법을 정리합니다.
-
버스 노선 공간 데이터에서 정류장 간 구간 형상 만들기 (Linear Referencing)
버스 노선의 선형과 정류장 좌표로 정류장 간 구간 형상을 만드는 과정을 설명합니다. Linear Referencing으로 정류장을 Measure로 바꾸고 두 Measure 사이를 추출합니다.
-
억울한 EXISTS, 정말 IN보다 느릴까?
EXISTS를 IN으로 바꾸면 빨라진다는 통념을 따져봅니다. 성능 개선과 원인 입증은 다른 문제라는 것, 그리고 동등한 서브쿼리 IN과 EXISTS가 현대 MySQL에서 같은 최적화 후보가 되는 것을 로컬 실측으로 확인합니다.
-
JPA에서 유니크한 관계에 유니크키를 걸었는데 Duplicate entry가 나는 이유: Hibernate flush 순서
컬렉션을 clear()로 비우고 새로 채우는 교체 패턴에 유니크키를 얹으면 Duplicate entry가 납니다. Hibernate가 삭제를 마지막에 실행하는 flush 순서를 공식 문서와 소스를 근거로 정리하고, 유니크키를 유지하면서 교체하는 방법을 다룹니다.
-
클로드는 프롬프트 캐싱을 어떻게 할까: Claude Code 사용량이 빨리 소진되는 이유
Claude Code는 매 요청마다 전체 컨텍스트를 다시 전송합니다. 서버는 요청의 앞부분이 이전과 정확히 일치할 때만 재계산을 생략합니다. 공식 문서를 근거로, 이 일치가 무너지는 조건과 그때의 비용을 정리합니다.
-
데이터베이스 정규화 (6): 보이스-코드 정규형(BCNF), 모든 결정자를 후보키로
보이스-코드 정규형(BCNF)을 다룹니다. 3NF가 남긴 빈틈, 모든 결정자가 후보키여야 한다는 조건, 후보키가 겹치는 구조에서 생기는 중복을 예시와 함께 정리합니다.
-
데이터베이스 정규화 (5): 제3정규형(3NF), 이행적 함수적 종속 제거
제3정규형(3NF)을 다룹니다. 이행적 함수적 종속의 의미, Codd의 1971년 원문 정의, 그리고 키가 아닌 속성을 거쳐 생기는 중복을 제거하는 방법을 예시와 함께 정리합니다.
-
JPA 테스트가 CI에서 OOM으로 죽은 이유: Spring 컨텍스트 캐시 키와 H2
@DataJpaTest마다 서로 다른 H2 DB 이름을 주면 Spring 컨텍스트 캐시가 무력화되어 CI에서 OutOfMemoryError가 납니다. 원인인 컨텍스트 캐시 키(MergedContextConfiguration)의 동작과 해결 방법을 공식 문서, 소스를 근거로 정리합니다.
-
데이터베이스 정규화 (4): 제2정규형(2NF), 함수적 종속과 부분 함수적 종속 제거
제2정규형(2NF)을 다룹니다. 2NF의 토대인 함수적 종속성을 완전 함수적 종속, 부분 함수적 종속으로 나누어 설명하고, 복합키에서 생기는 부분 함수적 종속을 어떻게 제거하는지 예시와 함께 정리합니다.
-
데이터베이스 정규화 (3): 제1정규형(1NF), 원자값과 반복 그룹
제1정규형(1NF)을 자세히 다룹니다. 원자값의 의미와 흔한 오해, 반복 그룹을 분리하는 방법, 그리고 1NF가 아직 보장하지 못하는 것까지 예시와 함께 정리합니다.
-
데이터베이스 정규화 (2): 이상현상과 함수적 종속성, 왜 정규화가 필요한가
삽입, 갱신, 삭제 이상현상을 예시로 설명하고 MariaDB에서 직접 재현해, 데이터베이스가 막아주는 이상현상과 조용히 지나가는 이상현상을 구분합니다. 세 단계 분류를 컬럼 세 개에 저장한 실제 계약 테이블에서 갱신 이상이 어떻게 해마다 복제됐는지도 함께 다룹니다.
-
데이터베이스 정규화 (1): 정규화 전에, 데이터 무결성과 키부터
정규화를 둘러싼 흔한 오해 세 가지에서 출발해, 정규형에 들어가기 전 토대가 되는 개념을 정리합니다. 데이터 무결성의 종류(개체, 참조, 도메인)와 키의 계층(슈퍼키, 후보키, 자연키, 대리키), 그리고 키가 제약조건으로 동작하는 방식을 설명합니다.
-
JPA N+1 문제와 세 가지 해결법 비교 (@EntityGraph / JPQL / QueryDSL)
JPA에서 N+1 문제를 해결하는 @EntityGraph, JPQL fetch join, QueryDSL을 검증 시점, 안전성, 적합한 상황 기준으로 비교합니다. 언제 무엇을 쓸지 정리했습니다.