PostgreSQL에서의 RBO, CBO 과연 어떤 방식을 채택할까? 🤔

 

 

🔍 용어 정리

RBO (Rule-Based Optimizer) - 사람이 정의한 규칙 기반으로 쿼리 실행 계획을 고름
CBO (Cost-Based Optimizer) - 비용 기반으로 통계, 행 수 등을 고려해서 최적 계획 선택

 

 

PostgreSQL 얘기 전에 앞서

Oracle 에서는 8i 이하 버전에서 RBO를 채택하였고, 9i 버전에서는 CBO를 본격적으로 도입해 사용했다.

11g 버전이후 부터 RBO는 더 이상 사용이 불가능하게 되었고 현재까지 CBO 방식으로 사용하고 있다.

 

 

 

PostgreSQL은 RBO와 CBO 어떤 방식을 채택했을까

 

→ 답은 CBO 방식이다.

 

애초에 RBO를 공식적으로 채택해서 사용한 적이 없었다.

PostgreSQL 최초 버전인 6.0 버전(1997년)부터 CBO를 채택하여 사용하였다. 

 

그럼, PostgreSQL은 CBO 비용 계산 기준 요소는 다음과 같다.

항목 설명 기본값(postgresql.conf)
seq_page_cost 순차 I/O 1페이지 비용 1.0
random_page_cost 랜덤 I/O 1페이지 비용 4.0 (디스크 기준, SSD는 낮춤)
cpu_tuple_cost 튜플 한 개 처리 비용 0.01
cpu_index_tuple_cost 인덱스 튜플 처리 비용 0.005
cpu_operator_cost 연산자 1회 비용 0.0025
통계정보 ANALYZE로 수집된 통계 (row count, NDV 등) pg_statistic 뷰에 저장
해당 Cost들을 옵티마이저가 계산하여  Plan을 결정함.

 

 

위 Cost들을 기반으로, 어떤 실행계획을 수행할지 옵티마이저가 판단하고 옵티마이저는 DB버전이 올라갈 수록 성능이 뛰어날 수도 있다.(오히려 잘못된 Plan을 타는 경우도 간혹 있음) 따라서 Version에 따라 쿼리 수행 검증은 필수적으로 필요하며 개발자와 DBA간의 원활한 소통으로 검증 방식을 적절한 방법에 타협을 해야 한다.

 

 

PostgreSQL은 다양한 실행 계획을 생성해서 비교하고 가장 효율적인 것을 선택한다.

항목 설명
Seq Scan 테이블의 모든 튜플(행)을 순차적으로 스캔
→ 인덱스를 사용하지 않고 디스크 블록을 순서대로 읽음
Index Scan B-Tree 등의 인덱스를 사용해 필터 조건에 맞는 row만 빠르게 조회
Bitmap Heap Scan 여러 인덱스 조건을 비트맵으로 결합한 후, 실제 테이블에서 필요한 블록만 읽음
Nested Loop 하나의 테이블을 반복하면서 다른 테이블을 반복적으로 참조
→ 가장 기본적인 조인 알고리즘
Merge Join 두 입력 테이블이 정렬되어 있을 때 병렬적으로 병합
→ 마치 merge sort처럼 두 집합을 합쳐 조인
Hash Join 한 테이블을 메모리에 올려 해시 테이블로 만들고, 다른 테이블의 조인 키로 검색
옵티마이저는 최적의 실행 계획을 Cost가 적은 방법을 선택한다.

 

 

그럼 잘못된 Plan을 타는 경우에는 어떻게 해야될까?

Oracle은 힌트를 사용하면 되지만, PostgreSQL에서는 공식적으로 힌트를 지원하지 않는다.

그치만, 외부 확장 모듈인 pg_hint_plan를 사용하면 힌트를 사용할 수 있다. 

 

🤔 pg_hint_plan이란?

  • PostgreSQL에서 SQL 문 내에 힌트를 작성하여 쿼리 실행 계획을 강제하는 확장(extension) 기능
  • Oracle의 /*+ HINT */ 문법과 유사하게 동작함
  • PostgreSQL 공식 패키지는 아니지만, OSS community에서 활발히 유지보수 중 (by OSS Japan)
PostgreSQL에서 공식적으로 지원하지 않는 기능이지만, 상황이 불가피 하다면 사용을 막을 순 없을 것 같다.
애초에 테이블 설계와 적절한 인덱스를 생성해서 힌트를 기피하는 방법이 최선이 아닐까 싶다.  

 

 

 

🙌 댓글, 공감, 공유는 큰 힘이 됩니다! 😄

 

 

 

 

+ Recent posts