본문 바로가기

분류 전체보기53

대량 적재 다음 날 쿼리가 느려진 진짜 이유 대량 적재 다음 날 쿼리가 느려진 진짜 이유를, 통계(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.
복합 인덱스는 순서가 전부입니다 복합 인덱스는 순서가 전부입니다—leftmost prefix 규칙과 함께 컬럼 순서 설계를 정리한 글입니다. 데이터베이스를 15년 가까이 다루면서 가장 자주 마주친 성능 사고는 화려한 튜닝 실패가 아니라 복합 인덱스의 컬럼 순서 하나를 잘못 잡아 벌어진 일이었습니다. 인덱스를 분명히 만들었는데도 쿼리가 느리다는 제보를 받고 EXPLAIN을 열어보면, 인덱스가 아예 안 쓰이거나 딱 절반만 쓰이고 있던 경우가 부지기수였죠. 오늘은 그 순서라는 주제 하나만 붙잡고 이야기해 보려 합니다.leftmost prefix, 인덱스가 왼쪽부터 읽히는 규칙복합 인덱스를 이해하는 핵심은 딱 하나입니다. B-Tree 인덱스는 정의된 컬럼 순서대로 왼쪽부터 정렬되어 저장된다는 사실입니다. (a, b, c)로 인덱스를 만들면,.. 2026. 7. 7.
SELECT에 컬럼 하나 더했다가 느려진 이유, 커버링 인덱스 SELECT에 컬럼 하나를 더했더니 느려졌던 경험과 커버링 인덱스를 index-only scan 관점에서 정리한 글입니다. 잘 태운 쿼리가 밀리초 단위로 끝나다가, 어느 날 배포 이후 몇 초씩 걸리기 시작했습니다. diff를 보니 바뀐 건 딱 한 줄, SELECT 목록에 컬럼 하나가 추가된 것뿐이었죠. WHERE도 ORDER BY도 그대로였는데 왜 느려졌을까요. 범인은 조용히 깨진 index-only scan이었습니다. 오늘은 커버링 인덱스라는 최적화가 왜 그렇게 빠른지, 또 왜 그렇게 쉽게 무너지는지를 실제 사고 기록과 함께 정리해 보겠습니다.index-only scan은 왜 그렇게 빠른가일반적인 index scan은 두 단계로 움직입니다. 먼저 B-tree 인덱스를 타고 내려가 조건에 맞는 엔트리를.. 2026. 7. 7.