11.10. 연산자 클래스와 연산자 패밀리

11.10. 연산자 클래스와 연산자 패밀리

인덱스를 만들 때 각 컬럼에 어떤 연산자 클래스를 쓸지 지정할 수 있어요. 연산자 클래스는 그 컬럼의 인덱스가 어떤 연산자를 사용할지 결정하는 역할을 하죠. 기본적으로는 데이터 타입에 맞는 기본 연산자 클래스가 자동으로 적용되지만, 특별한 정렬이나 패턴 매칭이 필요할 때는 직접 골라줄 수도 있어요. 이번 절에서는 연산자 클래스와 그 상위 개념인 연산자 패밀리에 대해 알아볼게요.

출처: 공식문서

연산자 클래스란?

인덱스 정의에서 각 컬럼에 대해 연산자 클래스를 지정할 수 있어요. 문법은 다음과 같아요.

CREATE INDEX name ON table (column opclass [ ( opclass_options ) ] [ sort options ] [ , ... ]);

연산자 클래스는 해당 컬럼의 인덱스가 사용할 연산자를 결정해요. 예를 들어 int4 타입의 B-tree 인덱스는 int4_ops 클래스를 사용하는데, 이 클래스에는 int4 값들을 비교하기 위한 비교 함수들이 포함되어 있어요. 실무에서는 보통 컬럼 데이터 타입의 기본 연산자 클래스면 충분해요.

그런데 왜 이런 걸 따로 둔 걸까요? 어떤 데이터 타입은 의미 있는 인덱스 동작이 여러 가지일 수 있기 때문이에요. 예를 들어 복소수 타입을 절대값 기준으로 정렬할 수도 있고, 실수부 기준으로 정렬할 수도 있겠죠. 이럴 때 두 개의 연산자 클래스를 정의해 두고, 인덱스를 만들 때 적절한 클래스를 선택하면 돼요.

연산자 클래스는 기본 정렬 순서를 결정하며, 여기에 COLLATE, ASC/DESC, NULLS FIRST/NULLS LAST 같은 정렬 옵션을 추가로 붙여서 조정할 수도 있어요.

기본 제공 연산자 클래스들

기본 연산자 클래스 외에도 몇 가지 내장 연산자 클래스가 있어요.

  • text_pattern_ops: text 타입용
  • varchar_pattern_ops: varchar 타입용
  • bpchar_pattern_ops: char 타입용

이 클래스들은 기본 클래스와 달리 로케일별 정렬 규칙을 따르지 않고 문자 하나하나를 엄격하게 비교해요. 그래서 데이터베이스가 표준 C 로케일을 사용하지 않을 때 LIKE나 POSIX 정규 표현식 같은 패턴 매칭 쿼리에 적합해요.

예를 들어 varchar 컬럼에 다음과 같이 인덱스를 만들 수 있어요.

CREATE INDEX test_index ON test_table (col varchar_pattern_ops);

주의할 점이 있어요. 일반적인 <, <=, >, >= 비교 쿼리가 인덱스를 사용하려면 기본 연산자 클래스로 만든 인덱스도 별도로 만들어야 해요. xxx_pattern_ops 클래스는 이런 비교 쿼리에는 사용할 수 없거든요. 다만 동등 비교(=)에는 사용할 수 있어요. 같은 컬럼에 서로 다른 연산자 클래스로 여러 인덱스를 만드는 것도 가능해요.

만약 C 로케일을 사용한다면 xxx_pattern_ops 클래스가 필요 없어요. 기본 연산자 클래스 인덱스만으로도 패턴 매칭 쿼리를 처리할 수 있기 때문이에요.

정의된 모든 연산자 클래스를 확인하는 쿼리는 다음과 같아요.

SELECT am.amname AS index_method,
       opc.opcname AS opclass_name,
       opc.opcintype::regtype AS indexed_type,
       opc.opcdefault AS is_default
    FROM pg_am am, pg_opclass opc
    WHERE opc.opcmethod = am.oid
    ORDER BY index_method, opclass_name;

연산자 패밀리

연산자 클래스는 사실 더 큰 구조인 연산자 패밀리의 부분집합이에요. 여러 데이터 타입이 비슷한 동작을 보일 때, 타입 간(cross-data-type) 연산자를 정의하고 이