Generated Columns

Generated Columns

"다른 열 값으로부터 항상 계산되는 열"이 있으면 편한 경우가 있어요. 예를 들어 키를 cm 단위로 저장했는데 인치 단위로도 보여주고 싶을 때요. generated column은 바로 그런 특별한 열이에요. 다른 열들로부터 항상 계산되는 열이고, 테이블에 대한 뷰(view)이 열 버전이라고 생각하면 돼요.

출처: 공식문서

STORED vs VIRTUAL

generated column에는 두 종류가 있어요: stored와 virtual.

  • stored generated column — 행이 쓰일 때(삽입·갱신) 계산되어, 일반 열처럼 저장 공간을 차지해요.
  • virtual generated column — 저장 공간을 차지하지 않고, 읽을 때 계산돼요.

그래서 virtual generated column은 뷰와 비슷하고, stored generated column은 구체화된 뷰(materialized view)와 비슷하다고 볼 수 있어요. 단, stored 쪽은 항상 자동으로 갱신된다는 차이가 있죠.

만들기

generated column을 만들려면 CREATE TABLE 안에서 GENERATED ALWAYS AS 절을 사용해요:

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm / 2.54)
);

기본적으로 generated column은 virtual 종류이에요. 명시적으로 선택하고 싶다면 VIRTUAL이나 STORED 키워드를 쓰면 돼요.

쓸 수 없다(DIRECT WRITE 불가)

generated column에는 직접 값을 쓸 수 없어요. INSERTUPDATE 명령에서 generated column에 값을 지정할 수 없고, 대신 DEFAULT 키워드는 지정할 수 있어요.

기본값이 있는 열과의 차이

기본값이 있는 열과 generated column은 꽤 달라요.

  • 기본값은 행이 처음 삽입될 때 다른 값이 주어지지 않았다면 딱 한 번 평가돼요. generated column은 행이 바뀔 때마다 갱신되고 덮어쓸 수 없어요.
  • 열 기본값은 테이블의 다른 열을 참조할 수 없어요. 반면 생성 표현식(generation expression)은 보통 다른 열을 참조하죠.
  • 열 기본값은 random()이나 현재 시각을 참조하는 함수 같은 휘발성(volatile) 함수를 쓸 수 있어요. generated column에는 그게 허용되지 않아요.

생성 표현식의 제약 조건

generated column과 테이블 정의에는 몇 가지 제약이 따라와요.

  • 생성 표현식은 immutable(불변) 함수만 사용할 수 있고, 서브쿼리나 현재 행 이외의 어떤 것도 참조할 수 없어요.
  • 생성 표현식은 다른 generated column을 참조할 수 없어요.
  • 생성 표현식은 tableoid를 제외한 시스템 열을 참조할 수 없어요.
  • virtual generated column은 사용자 정의 타입을 가질 수 없고, 생성 표현식도 사용자 정의 함수·타입을 참조하지 못해요. 즉 내장 함수·타입만 쓸 수 있죠. (이 제한은 stored generated column에는 없어요.)
  • generated column은 열 기본값이나 identity 정의를 가질 수 없어요.
  • generated column은 파티션 키(partition key)의 일부가 될 수 없어요.
  • 외부 테이블(foreign table)은 generated column을 가질 수 있어요. (CREATE FOREIGN TABLE 참고.)

상속과 파티셔닝

부모 열이 generated column이면 자식 열도 같은 종류(stored 또는 virtual)의 generated column이어야 해요. 다만 자식 열의 생성 표현식은 달라도 돼요. 반대로 부모 열이 generated column이 아니라면 자식 열도 generated면 안 돼요.

  • stored generated column의 경우 행 삽입·갱신 시 실제로 적용되는 생성 표현식은 그 행이 물리적으로 들어있는 테이블과 연관된 것이에요.
  • CREATE TABLE ... INHERITSCREATE TABLE ... PARTITION OF에서 GENERATED 절 없이 자식 열 정의를 쓰면, GENERATED 절이 부모로부터 자동 복사돼요.
  • 다중 상속에서 부모 열 하나가 generated column이라면 모든 부모 열이 generated column이어야 해요. 생성 표현식이 전부 같지 않다면 자식의 원하는 표현식을 명시적으로 지정해야 해요.

권한과 동작상 주의점

generated column은 기본 베이스 열과는 별도로 접근 권한을 유지해요. 그래서 특정 역할이 기반 열에는 접근하지 못해도 generated column은 읽을 수 있게 구성할 수 있어요. 다만 virtual의 경우 생성 표현식이 leakproof 함수만 쓸 때 완전히 안전하지만, 시스템이 이를 강제하진 않아요.

생성 표현식에 쓰인 함수의 권한은 표현식이 실제로 실행될 때 검사돼요. 함수가 SECURITY INVOKER인지 SECURITY DEFINER인지에 따라 쿼리를 실행하는 사용자 또는 함수 소유자의 권한으로 실행되죠.

generated column은 개념상 BEFORE 트리거가 실행된 뒤 갱신돼요. 그래서 BEFORE 트리거에서 베이스 열을 바꾸면 그 변경이 generated column에 반영돼요. 반대로 BEFORE 트리거에서 generated column에 접근하는 것은 허용되지 않아요.

논리적 복제

generated column은 CREATE PUBLICATIONpublish_generated_columns 파라미터에 따라, 또는 CREATE PUBLICATION 명령의 열 목록에 포함시켜 논리적 복제를 통해 복제될 수 있어요. 이 기능은 현재 stored generated column에서만 지원돼요. (29.6절 참고.)

더 알아보기 (Learn more)