PostgreSQL 문서
PostgreSQL 18 문서에서 모델이 틀리기 쉬운 규칙들: 놀라운 기본값, 잠금 및 동시성 함정, PostgreSQL 18 변경 사항 및 문서가 권장하는 패턴입니다. 모든 규칙은 이를 뒷받침하는 문서 URL로 끝납니다.
다루는 버전
참조는 PostgreSQL 18 문서(마이너 릴리스 18.6)를 따릅니다. 18부터만 유효한 사실은 "PostgreSQL 18"이라고 표시합니다. 먼저 서버 버전을 확인하세요. 이전 서버에서는 모든 "PostgreSQL 18" 규칙을 사용할 수 없는 것으로 간주하세요.
탐색 방법
작업에 필요한 참조만 아래 표에서 읽으세요. 출처: SOURCES.md.
빠른 규칙
- PostgreSQL 18에서 키워드 없는 생성(generated) 컬럼은 VIRTUAL이며, 읽을 때 계산됩니다. 통계나 논리 복제를 위해
STORED를 작성하세요. https://www.postgresql.org/docs/18/ddl-generated-columns.html https://www.postgresql.org/docs/18/sql-altertable.html serial대신 식별(identity) 컬럼을 사용하세요. 식별 컬럼은 NOT NULL이지만 고유하지는 않습니다: PRIMARY KEY를 추가하세요. https://www.postgresql.org/docs/18/ddl-identity-columns.html- 모든 외래 키의 참조하는 컬럼을 직접 인덱싱하세요. PostgreSQL은 참조되는 쪽만 인덱싱합니다. https://www.postgresql.org/docs/18/ddl-constraints.html
- 일반
CREATE INDEX는 전체 빌드 동안 쓰기를 차단합니다. 라이브 테이블에서는 트랜잭션 블록 밖에서CREATE INDEX CONCURRENTLY를 사용하고, 실패 시 남은 INVALID 인덱스를 삭제하세요. https://www.postgresql.org/docs/18/sql-createindex.html - 큰 테이블에 제약 조건을
NOT VALID로 추가한 다음VALIDATE CONSTRAINT를 실행하세요. 이는 쓰기를 차단하지 않습니다. PostgreSQL 18은 NOT NULL에도 이를 허용합니다. https://www.postgresql.org/docs/18/sql-altertable.html - 변동 가능한(volatile) 기본값, 저장된 생성(stored generated) 컬럼 또는 식별자를 가진
ADD COLUMN은 ACCESS EXCLUSIVE 아래에서 전체 테이블을 다시 씁니다. 비변동 기본값은 그렇지 않습니다. https://www.postgresql.org/docs/18/sql-altertable.html - 마이그레이션 세션에는
lock_timeout을 설정하고,statement_timeout,lock_timeout,transaction_timeout은 역할 또는 세션별로 설정하며, 전역으로 설정하지 마세요. https://www.postgresql.org/docs/18/runtime-config-client.html INSERT ... ON CONFLICT (cols) DO UPDATE로 업서트하세요. 이는 READ COMMITTED에서 항상 동시성 하에서 삽입하거나 업데이트합니다. MERGE는 다른 세션이 동일한 키를 삽입할 때 고유 위반으로 실패할 수 있습니다. https://www.postgresql.org/docs/18/transaction-iso.html- SQLSTATE 40001 및 40P01에서 전체 트랜잭션을 재시도하세요. PostgreSQL은 자체적으로 재시도하지 않습니다. 메시지가 아닌 SQLSTATE를 테스트하세요. https://www.postgresql.org/docs/18/mvcc-serialization-failure-handling.html
- 기본 격리 수준은 READ COMMITTED입니다: 각 명령문은 새 스냅샷을 봅니다. 여러 행의 비즈니스 규칙은 SERIALIZABLE 또는 명시적 잠금이 필요합니다. https://www.postgresql.org/docs/18/transaction-iso.html https://www.postgresql.org/docs/18/applevel-consistency.html
- 작업 큐에는
SELECT ... FOR UPDATE SKIP LOCKED를 사용하고, 키가 변경되지 않을 때는FOR NO KEY UPDATE를 사용하세요. https://www.postgresql.org/docs/18/sql-select.html https://www.postgresql.org/docs/18/explicit-locking.html - 리스트나 서브쿼리에 NULL이 있는
NOT IN은 절대 참이 아닙니다.count이외의 집계 함수는 0행에 대해 NULL을 반환합니다. https://www.postgresql.org/docs/18/functions-comparisons.html https://www.postgresql.org/docs/18/functions-aggregate.html - 페이지네이션과
LIMIT는 고유 키에 대한 ORDER BY가 필요합니다. 그렇지 않으면 실행마다 결과가 다릅니다. https://www.postgresql.org/docs/18/queries-limit.html - 시점(instants)을
timestamptz로 저장하세요.TIMESTAMP '2004-10-19 10:23:54+02'는 시간대가 없는 타임스탬프이며 오프셋이 제거됩니다. https://www.postgresql.org/docs/18/datatype-datetime.html now()는 트랜잭션 시작 시간입니다. 실제 시간을 얻으려면clock_timestamp()를 사용하세요. 문자열'now'를 기본값으로 절대 사용하지 마세요. https://www.postgresql.org/docs/18/functions-datetime.htmljsonb를 사용하고@>쿼리를 위해GIN (col jsonb_path_ops)로 인덱싱하세요. 인덱스가 사용되려면 연산자가 인덱싱된 표현식에 적용되어야 합니다. https://www.postgresql.org/docs/18/datatype-json.html- PostgreSQL 18은
gen_random_uuid()옆에 시간 정렬 UUID인uuidv7()을 추가합니다. https://www.postgresql.org/docs/18/functions-uuid.html - PostgreSQL 18
RETURNING은 INSERT, UPDATE, DELETE 및 MERGE에서old.col과new.col을 읽습니다. https://www.postgresql.org/docs/18/dml-returning.html EXPLAIN ANALYZE는 명령문을 실행합니다: 쓰기를BEGIN ... ROLLBACK으로 감싸세요. PostgreSQL 18에서는 BUFFERS를 자동으로 포함합니다. https://www.postgresql.org/docs/18/sql-explain.html https://www.postgresql.org/docs/18/using-explain.html- 다중 컬럼 B-트리는 PostgreSQL 18에서 선행 컬럼 없이 쿼리에 서비스할 수 있지만(스킵 스캔), 해당 컬럼의 고유 값이 적은 경우에만 가능합니다. https://www.postgresql.org/docs/18/indexes-multicolumn.html
- 자동 진공(autovacuum)을 켜두고 VACUUM FULL을 피하세요. 자동 진공은 분할 테이블이나 임시 테이블을 분석하지 않습니다: 직접 ANALYZE하세요. https://www.postgresql.org/docs/18/routine-vacuuming.html
ENABLE ROW LEVEL SECURITY가 있어야 행 수준 보안이 작동하며,FORCE ROW LEVEL SECURITY가 없으면 테이블 소유자는 이를 우회합니다. https://www.postgresql.org/docs/18/ddl-rowsecurity.html- SECURITY DEFINER 함수는
SET search_path = trusted_schema, pg_temp가 필요하며 동일한 트랜잭션에서 PUBLIC으로부터 EXECUTE를 취소해야 합니다. https://www.postgresql.org/docs/18/sql-createfunction.html - 테이블에 대한 권한 부여는 해당 테이블이 사용하는 시퀀스(serial 컬럼의 시퀀스 포함)로 확장되지 않습니다. 별도로 시퀀스 권한을 설정하세요. https://www.postgresql.org/docs/18/sql-grant.html
- 클라이언트는 기본적으로
sslmode=prefer로 설정되어 서버를 확인하지 않습니다.sslmode=verify-full을 사용하세요. https://www.postgresql.org/docs/18/libpq-ssl.html - 동적 SQL을
format('%I', ident)와EXECUTE ... USING으로 값에 대해 작성하고, 절대 연결(concatenation)하지 마세요. https://www.postgresql.org/docs/18/plpgsql-statements.html - 전문(full-text) 표현식 인덱스는 2-인수
to_tsvector('english', col)를 사용해야 하며, 쿼리는 정확히 그 형식을 반복해야 합니다. https://www.postgresql.org/docs/18/textsearch-tables.html
참조
| 참조 | 읽어야 할 때 |
|---|---|
| schema-design.md | 테이블 생성: 식별자 및 시퀀스, 생성 컬럼, 제약 조건, 시간 키, 도메인, 스키마 및 search_path, 파티셔닝 설계 |
| migrations-and-locks.md | 마이그레이션 작성: ALTER TABLE 잠금 수준 및 다시 쓰기, NOT VALID, 동시 인덱스 빌드, REINDEX, 파티션 연결 및 분리 |
| data-types.md | 숫자, 텍스트, bytea, enum, UUID, 배열 또는 범위 타입 선택, 범위에 대한 배타 제약 조건 |
| datetime.md | 타임스탬프, 시간대, 간격, extract, date_trunc, to_char, to_timestamp 관련 모든 것 |
| json.md | JSONB 저장, 쿼리, 인덱싱 또는 업데이트, jsonpath, JSON_VALUE, JSON_TABLE, JSON 집계 함수 |
| queries.md | SELECT 로직: NULL 의미론, 조인, LATERAL, 그룹화, 집계 함수, 윈도우 함수, 페이지네이션, UNION, CTE |
| writes.md | INSERT ON CONFLICT, UPDATE 및 DELETE 조인, 대규모 변경 일괄 처리, RETURNING, MERGE, COPY, 대량 로드 |
| indexes.md | 인덱스 선택 또는 검토: 타입, 컬럼 순서, 스킵 스캔, 부분, 표현식, INCLUDE, pattern_ops, GIN, BRIN |
| concurrency.md | 격리 수준, 재시도, 행 및 테이블 잠금, 교착 상태, 조언 잠금, 타임아웃, LISTEN 및 NOTIFY |
| performance.md | EXPLAIN 읽기, 통계 및 확장 통계, 진공, 메모리 및 플래너 설정, 병렬 쿼리, pg_stat_statements |
| security.md | GRANT 및 기본 권한, 역할, 행 수준 보안, SECURITY DEFINER, 비밀번호, TLS 및 libpq 연결 매개변수 |
| plpgsql-triggers.md | 함수 작성, PL/pgSQL, 동적 SQL, 예외, 트리거, 프로시저 |
| text-search.md | 문자열 함수, LIKE 및 정규식, 따옴표 처리, tsvector를 사용한 전문 검색, 순위 매기기, ts_headline |
업그레이드 시 염두에 둘 PostgreSQL 18 변경 사항
initdb는 기본적으로 데이터 체크섬을 활성화하며,pg_upgrade는 일치하는 설정이 필요합니다. https://www.postgresql.org/docs/18/release-18.html- 분할 테이블에 대한 VACUUM 및 ANALYZE는 해당 파티션도 처리합니다. 부모만 처리하려면
ONLY를 작성하세요. https://www.postgresql.org/docs/18/release-18.html pg_upgrade는 플래너 통계를 유지하지만 확장 통계는 유지하지 않습니다. https://www.postgresql.org/docs/18/release-18.html- AFTER 트리거는 이벤트가 대기열에 추가될 때 활성화된 역할로 실행됩니다. https://www.postgresql.org/docs/18/release-18.html
- 비동기 I/O(
io_method, 기본worker),effective_io_concurrency기본값은 16입니다. https://www.postgresql.org/docs/18/runtime-config-resource.html
이전 패턴
| 이전 | 현재 |
|---|---|
기본값의 'now' 또는 'today' 리터럴 | now(), CURRENT_DATE (https://www.postgresql.org/docs/18/datatype-datetime.html) |
MD5 비밀번호, password 인증 방법 | scram-sha-256 (https://www.postgresql.org/docs/18/auth-password.html) |