본문 바로가기

전체 글11


PostgreSQL이 디스크를 SSD로 바꿔도 안 빨라진다면 — shared_buffers·work_mem 메모리 파라미터부터 의심하라 **문제 상황**정렬이 들어간 집계 쿼리 하나가 유독 느리다는 티켓이 올라왔다. `ORDER BY`와 `GROUP BY`가 같이 걸린 리포트 쿼리인데, 인덱스도 걸려 있고 통계정보도 최신인데 실행 시간이 들쭉날쭉하다. `EXPLAIN (ANALYZE, BUFFERS)`를 찍어보니 `Sort Method: external merge Disk: 184320kB`라는 줄이 눈에 띈다. 정렬 작업이 메모리 안에서 끝나지 못하고 디스크로 스필(spill)되고 있다는 뜻이다. 서버 RAM은 64GB나 되는데 정작 쿼리는 디스크 정렬을 하고 있었던 것이다. 이런 증상은 인덱스나 쿼리 구조 문제가 아니라 대부분 메모리 파라미터가 기본값 근처에 방치되어 있을 때 나온다.PostgreSQL을 설치 직후 설정 그대로 운영.. 2026. 7. 20.
Oracle 실행계획이 어느 날 갑자기 바뀌었다면 — 옵티마이저 통계와 SQL Plan Baseline으로 잡는 법 지난주에 어떤 팀 채팅방에서 "새벽에 배치 돌리는 쿼리가 갑자기 30분 넘게 걸린다"는 얘기가 나왔다. 코드는 손댄 적이 없고, 인덱스도 그대로였다. 범인은 결국 매일 밤 자동으로 도는 통계 수집 잡(auto stats job)이었다. 이런 일이 낯설지 않은 분들을 위해 오늘은 Oracle에서 실행계획이 통계 때문에 갑자기 뒤집히는 원리와, 이걸 재발하지 않게 막는 SQL Plan Baseline까지 정리해본다.## 증상: 코드는 그대로인데 쿼리가 느려졌다가장 흔한 패턴은 이렇다. `ORDERS` 테이블에서 `WHERE STATUS = 'PENDING'` 조건으로 조회하는 쿼리가 몇 달째 인덱스 레인지 스캔으로 빠르게 돌다가, 어느 날부터 갑자기 풀 테이블 스캔으로 바뀌면서 느려진다. 코드 배포 이력도 .. 2026. 7. 19.
쿼리는 빠른데 앱이 멈춘다? PostgreSQL 락 경합, pg_locks로 잡는 법 ## 문제 상황EXPLAIN ANALYZE로 확인해보면 쿼리 자체는 몇 밀리초면 끝나는데, 실제 애플리케이션에서는 그 쿼리가 몇 초, 심하면 몇 분씩 걸리는 것처럼 보이는 경우가 있다. 이럴 때 로그를 보면 실행계획에는 아무 문제가 없고, pg_stat_activity를 조회했을 때 상태가 `active`가 아니라 계속 `active`인데 CPU는 거의 안 쓰고 있거나, 애초에 쿼리가 시작도 못 하고 대기 큐에 걸려 있는 걸 보게 된다. 이건 십중팔구 실행계획 문제가 아니라 락(lock) 경합 문제다. 인덱스를 아무리 잘 만들어도, 다른 세션이 같은 로우나 테이블에 락을 걸고 커밋을 안 하고 있으면 뒤따르는 쿼리는 그냥 줄을 서서 기다릴 수밖에 없다.## PostgreSQL 락의 종류와 충돌 매트릭스Po.. 2026. 7. 18.
PostgreSQL 테이블이 수억 건 넘어갈 때, 파티셔닝을 도입하기 전에 알아야 할 것들 로그성 테이블이든 주문/거래 테이블이든, 행 수가 수천만 건을 넘어가면 어느 순간부터 똑같은 쿼리가 눈에 띄게 느려지는 구간이 온다. 인덱스를 아무리 손봐도 개선이 안 되고, VACUUM 한 번 도는 데 몇 시간씩 걸리기 시작하면 그때부터는 파티셔닝을 고려할 타이밍이다. 다만 파티셔닝은 "일단 걸어두면 빨라지는" 마법이 아니라, 쿼리 패턴과 딱 맞아떨어져야 효과를 보는 기법이라 도입 전에 정확히 이해하고 들어가는 게 중요하다.## 파티셔닝이 실제로 해결하는 문제큰 테이블을 여러 개의 물리적 조각(파티션)으로 나눠서 저장하면 크게 세 가지가 좋아진다.첫째, 쿼리가 파티션 키로 필터링될 때 옵티마이저가 관련 없는 파티션을 아예 스캔 대상에서 제외한다. 이걸 파티션 프루닝(partition pruning)이라.. 2026. 7. 17.
PostgreSQL 인덱스, B-tree만 쓰고 있다면 놓치고 있는 것들 (GIN·GiST·BRIN 실전 가이드) **문제 상황: 인덱스를 만들었는데 왜 안 먹히지**PostgreSQL을 쓰다 보면 이런 상황을 꼭 한 번은 만난다. `CREATE INDEX`로 인덱스를 만들었는데 `EXPLAIN`을 찍어보면 여전히 `Seq Scan`이 나온다. JSONB 컬럼에 `WHERE data @> '{"status": "active"}'` 조건을 걸었는데 일반 B-tree 인덱스는 아예 이 연산자를 지원하지 않아서 무시당한다. `LIKE '%검색어%'` 검색이 테이블이 커질수록 선형으로 느려진다. 시계열 로그 테이블에 수억 건이 쌓이는데 B-tree 인덱스 크기가 원본 테이블만큼 커져서 디스크와 캐시를 잡아먹는다.이런 문제들이 반복되는 이유는 하나다. PostgreSQL에는 B-tree 말고도 Hash, GIN, GiST, .. 2026. 7. 16.
쿼리가 갑자기 느려졌을 때, Oracle 대기 이벤트로 원인을 찾는 법 "어제 오후 2시쯤 배치가 갑자기 느려졌는데 원인을 모르겠다"는 문의를 받으면, 실행계획만 봐서는 답이 안 나오는 경우가 많습니다. 실행계획은 옵티마이저가 "이렇게 실행하겠다"는 계획일 뿐이고, 실제로 그 시점에 세션이 뭘 기다리느라 시간을 썼는지는 대기 이벤트(Wait Event)를 봐야 나옵니다. 오늘은 Oracle에서 이 대기 이벤트를 어떻게 진단에 활용하는지 정리해봅니다.1. 문제 상황: 실행계획은 정상인데 느리다 -- 실행계획상으로는 인덱스를 잘 타고 있는데 체감 속도가 느림SELECT * FROM orders WHERE customer_id = 12345;EXPLAIN PLAN으로 확인한 계획은 인덱스 스캔으로 정상인데, 실제 실행 시간은 평소보다 훨씬 오래 걸립니다. 이런 경우 문제는 쿼리 .. 2026. 7. 15.
지운 데이터가 왜 용량을 차지할까 — PostgreSQL VACUUM과 테이블 블로트 제대로 이해하기 며칠 전에 "분명 대량 삭제했는데 왜 테이블 용량이 그대로냐"는 질문을 받았습니다. DELETE나 UPDATE를 아무리 돌려도 디스크 사용량이 줄지 않는 상황, PostgreSQL 써본 분들이라면 한 번쯤 겪어봤을 겁니다. 이게 버그가 아니라 PostgreSQL의 핵심 동작 방식(MVCC) 때문에 생기는 정상적인 현상이라는 걸 알아야 VACUUM을 제대로 이해할 수 있습니다.1. 문제 상황: 지워도 줄지 않는 테이블 -- 100만 건짜리 로그 테이블에서 오래된 데이터 30만 건 삭제 DELETE FROM access_logs WHERE created_at 분명 30만 건을 지웠는데, pg_total_relation_size('access_logs')로 확인해보면 용량이 거의 그대로입니다. 심지어 시간이 .. 2026. 7. 15.
OFFSET 페이지네이션이 뒷페이지로 갈수록 느려지는 진짜 이유, 그리고 커서 기반으로 바꾸는 법 - 심화 게시판이나 어드민 목록 화면 만들 때 LIMIT 20 OFFSET 100 이런 식으로 페이지네이션 짜본 적 다들 있으실 겁니다. 저도 처음엔 별생각 없이 이렇게 짰다가, 데이터가 몇십만 건 쌓이고 나서 "왜 뒷페이지로 갈수록 목록 로딩이 느려지냐"는 문의를 받고 나서야 원인을 제대로 파봤습니다. 결론부터 말하면 OFFSET 자체가 구조적으로 뒷페이지에서 손해를 보는 방식이고, 이건 인덱스를 아무리 잘 걸어도 근본적으로 피할 수 없는 문제입니다. 오늘은 왜 그런지, 그리고 실무에서 어떻게 바꾸는지 코드로 정리해봅니다.1. 문제 상황: 100만 건짜리 게시글 테이블 CREATE TABLE posts ( id BIGINT PRIMARY KEY, title TEXT, created_at TIMESTA.. 2026. 7. 12.
OFFSET 페이지네이션이 느려지는 이유, 그리고 커서 기반으로 바꾸는 법 게시판이나 목록 API에 페이지네이션 넣다 보면 다들 한 번쯤 겪는 문제가 있습니다. 초반 페이지는 쌩쌩한데, 뒤로 갈수록 쿼리가 점점 느려지는 거요. 페이지 1은 5ms, 페이지 500은 800ms 이런 식으로요.원인은 OFFSET의 동작 방식흔히 쓰는 방식은 이렇습니다.SELECT * FROM posts ORDER BY created_at DESC LIMIT 20 OFFSET 100000; 문제는 OFFSET이 "100000번째부터 보여줘"가 아니라 "앞의 100000개를 읽고 버린 다음에 20개를 보여줘"라는 뜻이라는 겁니다. 인덱스가 있어도 스캔 자체는 앞에서부터 순서대로 해야 하니, OFFSET 값이 커질수록 읽어서 버리는 행이 계속 늘어나요. EXPLAIN ANALYZE로 찍어보면 실제로 이 .. 2026. 7. 11.
PostgreSQL 서버 세션 모니터링 및 락 확인, 세션 킬 기능 PostgreSQL에서 "pg_stat_activity" 뷰 는 데이터베이스 서버의 세션 모니터링이 가능하다. 이 뷰를 통해 현재 실행 중인 쿼리, 세션 정보 및 다양하고 유용한 정보를 얻을 수 있다. PostgreSQL에서 서버 세션을 모니터링은 다음 두 개의 파라미터와 관련이 있다. track_activities = on track_activity_query_size = 1024 파라미터 설명 track_activities 해당 파라미터를 설정 하면 모든 프로세스에서 실행 중인 현재 명령을 모니터링 할 수 있음 (default : on) track_activity_query_size 현재 실행 중인 쿼리의 텍스트를 저장하기 위해 예약된 메모리양 을 지정. 이 값을 단위 없이 지정하면 바이트로 간주됨... 2023. 11. 20.
PostgreSQL 대기 이벤트 조회 및 상세설명 PostgreSQL에서 "wait event"는 주로 성능 모니터링 및 튜닝에서 사용되는 개념이다. 이는 데이터베이스 시스템이 특정 이벤트를 완료할 때까지 대기하는 상태는 나타낸다. PostgreSQL에서 대기 이벤트를 확인해서 현재 어떤 원인에 의해 이벤트가 발생하는지 확인할 수 있다. PostgreSQL의 대기 이벤트를 조회하는 쿼리는 다음과 같다. SELECT pid, usename, application_name, query, state, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event is NOT NULL; PostgreSQL 대기 이벤트는 Wait Event Type과 Wait Event로 구분된다. Wait Event T.. 2023. 11. 20.