PostgreSQL 가이드와 튜토리얼
이 가이드들은 Postgres 자체를 다룹니다. 각 글은 운영 환경에서 실제로 마주칠 수 있는 문제에서 출발해, psql에 그대로 붙여 넣을 수 있는 SQL로 재현하고, 확인할 수 있는 해결 방법으로 끝납니다. 기준은 Relyt One이 실행하는 PostgreSQL 17이며, 내용 대부분은 최신 Postgres 전반에도 적용됩니다. 아래 읽기 순서를 따라 차례로 읽거나, 지금 겪는 문제에 맞는 가이드로 바로 이동하세요.
11 개의 글
여기서 시작하세요
권장하는 순서대로 네 편의 가이드를 소개합니다. 테이블을 잠그지 않고 스키마를 바꾸는 방법, 쿼리가 인덱스를 쓰게 하는 방법, 행 수준 보안의 빈틈을 막는 방법, 그리고 Postgres 18에서 옮겨 올 때 바뀌는 점입니다.
- PostgreSQL 마이그레이션 테이블 락: ALTER TABLE별로 어떤 락을 잡는지, 그리고 안전하게 배포하는 방법한 줄짜리 ALTER TABLE이 테이블의 모든 쿼리를 멈추게 하는 이유, PostgreSQL 17에서 흔한 마이그레이션이 각각 어떤 락을 잡고 어떤 것이 테이블을 다시 쓰는지, 그리고 운영 환경을 멈추지 않게 하는 lock_timeout, NOT VALID, CONCURRENTLY 패턴을 설명합니다.
- PostgreSQL이 인덱스를 사용하지 않는 이유 7가지: 직접 재현할 수 있는 EXPLAIN 출력과 함께인덱스를 만들었는데도 EXPLAIN에 순차 스캔이 나옵니다. PostgreSQL이 인덱스를 사용하지 않는 일곱 가지 이유(함수, 캐스트, 와일드카드, 선택도, 오래된 통계, 컬럼 순서, 작은 테이블)를 재현 방법과 해결책과 함께 설명합니다.
- 행 수준 보안이 조용히 뚫리는 다섯 가지 경우행 수준 보안은 깜빡한 WHERE 절에 대한 최고의 방어책입니다. 조용히 적용을 멈추기 전까지는 그렇습니다. PostgreSQL 17에서 행 수준 보안이 뚫리는 다섯 가지 경우를 재현 방법, 해결책, CI에서 잡아내는 카탈로그 쿼리와 함께 소개합니다.
- Postgres 18에서 오셨나요? Postgres 17에서 바꿔야 할 것들Relyt One은 PostgreSQL 17에서 실행됩니다. 스키마나 습관이 Postgres 18에서 왔다면, 17에서 무엇이 실패하는지, 대신 무엇을 써야 하는지, 18에서 만든 덤프를 어떻게 불러오는지 소개합니다. 모든 코드는 두 버전에서 모두 실행했습니다.
Postgres 태그가 달린 다른 글
RSS 피드
Postgres ID가 번호를 건너뛰는 이유와 가져오기 후 "duplicate key" 오류를 고치는 방법
PostgreSQL의 serial 및 identity 열에서 빈 번호가 생기는 원인(롤백, ON CONFLICT, 장애, CACHE), 데이터를 가져온 뒤 삽입이 duplicate key value violates unique constraint로 실패하는 이유, 모든 시퀀스를 한 번에 재설정하는 쿼리, integer ID가 바닥날 때 일어나는 일, 그리고 빈 번호 없는 송장 번호를 다룹니다. 모든 문장은 Postgres 17.11에서 재현했습니다.

Postgres를 작업 큐로 쓰기: FOR UPDATE SKIP LOCKED를 제대로 쓰는 법
PostgreSQL 17에서 SELECT ... FOR UPDATE SKIP LOCKED로 백그라운드 작업 큐를 만드는 방법을 설명합니다. 단순한 SELECT 후 UPDATE가 같은 작업을 두 번 가져가는 이유, FOR UPDATE만으로는 워커가 기다리게 되는 이유, 리스와 재시도, LISTEN/NOTIFY, vacuum, 그리고 폴링하는 워커가 서버리스 컴퓨트에 미치는 영향을 다룹니다. 모든 문장은 Postgres 17.11에서 재현했습니다.

Postgres의 INSERT ... ON CONFLICT와 MERGE: 어떤 업서트를 쓸지, 그리고 각각이 내는 오류
PostgreSQL 17에서 언제 INSERT ... ON CONFLICT로 업서트하고 언제 MERGE를 써야 하는지, 동시성 상황에서 MERGE가 중복 키 오류로 실패하는 이유, 그리고 'cannot affect row a second time', 비어 있는 RETURNING, 'no unique or exclusion constraint matching the ON CONFLICT specification'을 해결하는 방법을 설명합니다. 모든 문장은 Postgres 17.11에서 재현했습니다.

PgBouncer 트랜잭션 풀링 뒤에서 깨지는 것들과 각각의 해결 방법
트랜잭션 풀러 뒤에서 'prepared statement already exists' 오류가 나고, 설정이 요청 사이에 새고, 어드바이저리 락이 아무것도 잠그지 못하는 이유를 PgBouncer 1.24와 PostgreSQL 17에서 재현하고, 각각의 해결 방법과 언제 직접 연결을 써야 하는지에 대한 규칙을 설명합니다.

Relyt One 관리형 인증 시작하기
Relyt One에서 다중 사용자 Next.js 앱을 만드는 단계별 가이드입니다. 브랜치에서 관리형 인증을 활성화하고, 사용자를 로그인시키고, @relyt/auth로 JWT를 검증하고, Postgres 행 수준 보안으로 사용자마다 행을 분리합니다.

Relyt One 관리형 인증, 미리 보기 공개
앱 사용자를 위한 가입, 로그인, 세션, 조직 기능이 브랜치 바로 옆에서 실행되고 사용자는 여러분의 데이터베이스에 저장됩니다. 토큰은 JWKS로 검증하는 수명이 짧은 EdDSA JWT이며, 나머지는 행 수준 보안이 처리합니다.

Relyt One 소개: 코드처럼 브랜치하는 서버리스 Postgres
Relyt One은 쓰기 시 복사(copy-on-write) 브랜치, 유휴 상태일 때 일시 중지되는 컴퓨트, 기본 제공 벡터 검색, 관리형 인증을 갖춘 서버리스 PostgreSQL 17입니다. 작동 방식과 함께, 로그인부터 브랜치된 데이터베이스까지 5분 만에 가는 방법을 소개합니다.
영어로 된 글을 더 볼 수 있습니다. 영어 글