본문 바로가기

전체 글52

읽기가 쓰기를 안 기다리는 비결, MVCC 읽기가 쓰기를 안 기다리는 비결, MVCC를 스냅샷과 버전 관리 관점에서 정리한 글입니다.왜 읽기는 쓰기를 기다리지 않아도 되는가대시보드 조회 API가 배치 작업이 도는 시간대에만 느려진다는 제보를 받았던 게 몇 년 전 일입니다. 처음 떠올린 그림은 단순했습니다. 배치가 큰 테이블을 통째로 갱신하니, 그 행을 읽으려는 조회 쿼리들이 갱신이 끝날 때까지 줄을 서서 기다린다는 시나리오였죠. 읽기와 쓰기가 같은 데이터를 두고 서로를 막는다, 저는 오랫동안 이게 데이터베이스의 자연스러운 동작이라고 믿고 있었습니다.그런데 PostgreSQL과 MySQL(InnoDB) 같은 요즘 데이터베이스는 그렇게 동작하지 않습니다. 핵심은 MVCC, 즉 다중 버전 동시성 제어(Multi-Version Concurrency Co.. 2026. 7. 13.
N+1 문제 - 목록 화면 하나에 쿼리가 300개 나가고 있었습니다 목록 화면 하나에 쿼리가 300개 나가고 있었습니다—N+1 문제와 배치 로딩을 정리한 글입니다.N+1은 어떻게 조용히 생기는가N+1은 이름부터 결과를 그대로 담고 있습니다. 목록을 한 번 조회하는 쿼리 1개, 그리고 그 목록의 각 항목마다 연관 데이터를 다시 읽는 쿼리 N개. 항목이 20개면 21개, 100개면 101개의 쿼리가 나가죠. 무서운 점은 이 패턴이 코드상으로는 전혀 위험해 보이지 않는다는 것입니다.주문 목록을 보여주는 아주 평범한 코드를 예로 들어보겠습니다.# 주문 목록 조회orders = Order.objects.filter(status="paid")for order in orders: # 반복문 안에서 회원 정보 접근 print(order.customer.name)order.c.. 2026. 7. 11.
대량 적재 다음 날 쿼리가 느려진 진짜 이유 대량 적재 다음 날 쿼리가 느려진 진짜 이유를, 통계(ANALYZE)와 플래너의 관계로 정리한 글입니다. 플래너는 무엇을 보고 플랜을 고르는가같은 SQL을 던져도 어제는 30ms에 끝나던 쿼리가 오늘은 20초를 잡아먹는 일이 있습니다. 인덱스도 그대로, 데이터도 크게 다르지 않은데 말이죠. 이 수수께끼를 풀려면 먼저 옵티마이저, 그중에서도 플래너(planner) 가 어떻게 실행 계획을 고르는지부터 짚어야 합니다.플래너는 테이블을 직접 열어 보고 판단하지 않습니다. 매번 수백만 행을 훑어 "이 조건에 몇 건이 걸리나"를 세는 건 너무 비싸니까요. 대신 데이터베이스가 미리 요약해 둔 통계(statistics) 를 근거로 추정합니다. 지도를 보고 길을 정하는 내비게이션과 비슷하죠. 실제 도로를 달려 보지 않아.. 2026. 7. 10.
EXPLAIN을 추정이 아니라 실제로 읽기 EXPLAIN을 추정이 아니라 실제로 읽기—cost·rows와 EXPLAIN ANALYZE로 간극을 확인하는 법을 정리한 글입니다. 느린 쿼리를 마주하면 많은 분들이 인덱스부터 추가합니다. 저도 오래 그랬죠. 하지만 인덱스를 던지기 전에 플래너가 무슨 생각으로 그 계획을 짰는지 먼저 읽어야 한다는 걸 여러 번 헛발질한 뒤에야 배웠습니다. 오늘은 EXPLAIN을 막연한 추정으로 흘려 보지 않고, EXPLAIN ANALYZE로 추정과 실제의 간극을 짚어 원인을 찾는 방법을 제 경험과 함께 정리해 보겠습니다.플래너가 보여 주는 추정을 먼저 읽습니다그냥 EXPLAIN만 붙이면 쿼리를 실행하지 않고 플래너의 계획, 즉 "이렇게 돌리면 이 정도 비용이 들 것 같다"는 추정만 돌려줍니다. 가장 먼저 눈에 들어오는 .. 2026. 7. 9.
포트폴리오 리밸런싱 계산기를 직접 만든 개발기 포트폴리오 리밸런싱 계산기를 직접 만든 개발기를, 데이터·계산 등 실제로 마주친 문제와 선택을 중심으로 정리했습니다. 쓸 만한 게 없어서 직접 만들었습니다주식·ETF를 목표 비중대로 맞추려면 "무엇을 몇 주 사고팔지"를 계산해야 하는데, 막상 해보면 손이 많이 갑니다. 현재가에 환율까지 얽히고, 정수 단위로 딱 떨어지지도 않죠. 스프레드시트로 매번하기가 번거로워서, 결국 도구를 하나 직접 만들기로 했습니다. 이 글은 그 과정에서 마주친 문제와 선택을 개발자 관점에서 정리한 기록입니다.기술 스택은 단순하게 잡았습니다. Next.js(App Router)로 프론트를 짜고, 별도 백엔드 DB 없이 사용자의 입력은 브라우저 localStorage에만 저장하도록 했죠. 시세 같은 외부 데이터만 서버리스라우트로 중.. 2026. 7. 8.
B-tree만 쓰다 만난 GIN·BRIN의 세계 B-tree만 쓰다 만난 GIN·BRIN의 세계를, 인덱스 타입별 강점과 선택 기준으로 정리한 글입니다. B-tree가 잘하는 것과 못하는 것데이터베이스를 오래 다뤄 온 분이라도, 인덱스라는 단어를 들으면 자동으로 B-tree를 떠올리는 경우가 많습니다. 저 역시 10년 넘게 PostgreSQL과 MySQL을 만지면서 CREATE INDEX 한 줄이면 세상 모든 성능 문제가 풀리는 줄 알았던 시절이 있었죠. B-tree가 워낙 범용적이라 그렇습니다. 정렬된 트리 구조 덕분에 동등 비교(WHERE id = 100), 범위 검색(BETWEEN, >, ), 그리고 ORDER BY 정렬까지 한 인덱스로 깔끔하게 처리해 줍니다. 대부분의 OLTP 워크로드에서 B-tree만으로 90%는 커버가 됩니다.문제는 나머지.. 2026. 7. 8.