프로그래밍/서버, DBMS

PostgreSQL search_path 기준 정리

포도알77 2026. 7. 2. 10:24

본문 중간의 쿠팡 추천 상품 구매시 쿠팡 파트너스에서 일정액의 수수료를 제공받습니다.

PostgreSQL search_path 기준 정리

search_path는 스키마를 생략한 이름을 PostgreSQL이 어떤 순서로 해석할지 정하는 설정이다. 2026년 7월 2일 기준 PostgreSQL 18 공식 문서를 보면 기본값은 "$user", public이며, 동일한 이름의 테이블·함수·타입이 여러 스키마에 있을 때 먼저 찾은 객체가 사용된다.

실무에서는 편의성보다 안전성과 예측 가능성이 더 중요하다. 이 글은 search_path가 새 객체 생성 위치에 어떤 영향을 주는지, pg_catalog와 임시 스키마가 어떻게 동작하는지, 언제 publicCREATE 권한을 걷어야 하는지만 기준 중심으로 정리한다.

search_path는 무엇을 결정할까?

항목 영향
스키마를 생략한 객체 참조 목록에서 먼저 찾은 스키마의 객체가 선택됨
스키마를 생략한 객체 생성 목록에서 첫 번째로 유효한 스키마에 생성됨
동일 이름 충돌 경로 앞쪽 스키마가 우선됨
권한 없는 스키마나 없는 스키마 조용히 무시됨

공식 문서는 search_path를 쉼표로 구분한 스키마 목록으로 설명한다. 존재하지 않는 스키마나 현재 사용자가 USAGE 권한이 없는 스키마는 무시된다. 따라서 설정 문자열만 보고 실제 탐색 순서를 단정하지 말고, 현재 세션에서는 current_schemas()로 해석 결과를 확인하는 편이 안전하다.

기본값 "$user", public는 어떻게 해석될까?

기본값의 첫 항목인 "$user"는 현재 사용자 이름과 같은 스키마로 치환된다. 다만 그런 스키마가 없거나 USAGE 권한이 없으면 무시된다. 두 번째 항목인 public은 새 데이터베이스에 기본으로 존재하는 스키마다.

그래서 사용자별 스키마를 따로 만들지 않았다면 대부분의 비정규화된 이름은 결국 public에서 해석된다. 반대로 사용자별 스키마를 만들고 public의 쓰기 권한을 정리해 두었다면 같은 기본값이라도 훨씬 안전한 구조가 된다.

새 객체는 어디에 만들어질까?

스키마를 명시하지 않고 CREATE TABLE, CREATE VIEW, CREATE FUNCTION 같은 명령을 실행하면 search_path에서 첫 번째로 유효한 스키마가 생성 대상이 된다. 그래서 팀 공용 데이터베이스에서 search_path를 느슨하게 두면 "왜 이 객체가 여기 생겼지?" 같은 문제가 반복되기 쉽다.

SHOW search_path;
SET search_path TO app, public;

CREATE TABLE orders (
  id bigint primary key
);

위 예시에서는 app 스키마가 존재하고 권한이 있다면 ordersapp.orders로 생성된다. 생성 위치를 항상 고정하고 싶다면 DDL에서는 app.orders처럼 스키마를 명시하는 쪽이 더 예측 가능하다.

pg_catalog와 임시 스키마는 왜 따로 봐야 할까?

공식 문서 기준 pg_catalogsearch_path에 쓰지 않아도 항상 탐색된다. 명시하지 않으면 경로에 적은 스키마들보다 먼저 탐색되고, 직접 경로 뒤쪽에 두면 사용자 정의 이름이 내장 이름보다 앞설 수 있다. 이 동작 때문에 함수나 연산자 이름 충돌은 단순한 가독성 문제가 아니라 동작 차이로 이어질 수 있다.

임시 스키마 pg_temp도 세션에 존재하면 항상 탐색되지만, 공식 문서는 이것이 relation과 data type 이름에만 적용되고 함수나 연산자 이름에는 적용되지 않는다고 설명한다. 즉, 임시 테이블 이름 충돌과 함수 이름 충돌은 같은 규칙으로 생각하면 안 된다.

 

 

보안 관점에서 가장 중요한 기준은 무엇일까?

PostgreSQL 공식 문서는 쓰기 가능한 스키마를 search_path에 넣는 행위를 신뢰 문제로 본다. 어떤 스키마에 대해 다른 사용자가 CREATE 권한을 가지고 있다면, 그 사용자는 같은 이름의 객체를 만들어 다른 사용자의 쿼리 동작을 바꾸거나 악의적인 SQL 함수를 실행시키는 방향으로 악용할 수 있다.

이 때문에 기본 경로에 public이 남아 있어도 괜찮은 환경은 단일 사용자 또는 서로 완전히 신뢰하는 소수 사용자 환경으로 한정된다. 여러 사용자가 함께 쓰는 데이터베이스라면 public에 대한 CREATE 권한을 재검토하고, 사용자별 전용 스키마 또는 애플리케이션 전용 스키마 중심으로 경로를 설계하는 편이 맞다.

PostgreSQL 15 이후에는 무엇이 달라졌을까?

PostgreSQL 18 공식 문서는 PostgreSQL 15 이상에서 기본 설정이 사용자별 private schema 패턴을 지원한다고 설명한다. 반면 14 이하에서 업그레이드된 데이터베이스나 이전 기본값을 유지한 환경은 public 스키마에 여전히 넓은 CREATE 권한이 남아 있을 수 있다.

REVOKE CREATE ON SCHEMA public FROM PUBLIC;

공식 문서가 권장하는 안전한 패턴은 먼저 모든 공개 스키마에서 공용 CREATE 권한을 제거하고, 각 사용자에게 자기 이름의 스키마를 주는 방식이다. 기본 "$user", public를 유지하더라도 이 구조라면 기본 탐색 경로가 훨씬 덜 위험해진다.

운영에서 무난한 선택 기준

상황 무난한 기준 이유
애플리케이션 DDL 관리 객체 생성 시 스키마를 명시 생성 위치가 세션 설정에 흔들리지 않음
다중 사용자 DB public의 공용 CREATE 권한 제거 검토 경로 오염과 이름 가로채기 위험을 줄일 수 있음
사용자별 작업 공간 필요 사용자 전용 스키마 + 기본 "$user", public 활용 기본값과 잘 맞고 충돌을 줄이기 쉬움
공용 객체 배포 별도 공유 스키마를 두고 필요 시만 경로에 추가 public에 모든 객체를 몰아넣는 것보다 통제가 쉬움

자주 헷갈리는 질문

Q. search_path에 없는 스키마의 객체는 못 쓰나?

그렇지는 않다. schema.table, schema.function()처럼 스키마를 명시하면 된다. search_path는 스키마를 생략했을 때의 탐색 규칙이다.

Q. search_path 문자열에 적힌 순서가 항상 실제 순서와 같나?

항상 그렇지는 않다. 존재하지 않는 스키마나 권한 없는 스키마는 무시되고, pg_catalog와 임시 스키마는 별도 규칙으로 탐색된다. 현재 세션 기준 실제 결과는 current_schemas()로 확인하는 편이 정확하다.

Q. 함수 이름 충돌도 임시 스키마가 먼저 잡나?

아니다. PostgreSQL 공식 문서는 임시 스키마의 자동 탐색이 relation과 data type 이름에만 적용되고, 함수와 연산자 이름에는 적용되지 않는다고 설명한다.

정리

search_path는 단순한 편의 설정이 아니라 객체 해석 순서와 기본 생성 스키마를 함께 결정하는 규칙이다. 같은 이름 충돌이 가능한 환경에서는 쿼리 결과뿐 아니라 실행 함수 자체가 달라질 수 있으므로, 다중 사용자 DB에서는 특히 신중하게 관리해야 한다.

2026년 7월 2일 기준 PostgreSQL 18 공식 문서만 놓고 보면, 무난한 기본 전략은 DDL에서 스키마를 명시하고, 다중 사용자 환경에서는 public의 공용 CREATE 권한을 검토하며, 필요하면 사용자별 스키마 패턴을 쓰는 것이다.

참고 자료

반응형
페이스북으로 공유카카오톡으로 공유카카오스토리로 공유트위터로 공유URL 복사