prisma에서 PostgreSQL의 generated column 사용하기

konu·2025년 8월 7일

데이터베이스

목록 보기
7/8
post-thumbnail

1. 들어가며

인기 상품 리스트 조회를 구현해야 했다.
상품은 지난 일주일 간 판매량을 가진 A 그룹과 그렇지 않은 B 그룹으로 나뉜다.
B 그룹은 총 (판매 가격 * 판매 수량)으로 계산한다.

 

처음에는 ...

ORDER BY price * count

아무렇지 않게 위처럼 썼다.
그랬더니 모든 상품에 대해 연산해야 했고, 그래서 쿼리가 너무너무 느렸다.

그렇다고 total_sale 컬럼을 따로 둬서 관리하자니

  • 상품 저장
  • 상품 구매
  • 상품 판매 수량 수정
  • 상품 가격 수정
    ...

등등등 관리 포인트가 곳곳으로 늘어났다.

 

그래서 ...

PostgreSQL의 generated column 기능을 활용하기로 했다.

 

 

2. generated column

generated column은 다른 컬럼으로부터 연산되어 값이 채워지는 컬럼을 뜻한다.
그래서 사실상 뷰 테이블의 컬럼 버전이라고 볼 수 있겠다.

generated column은 실제 데이터를 써서 저장되는 STORED
읽을 때 계산해서 주는 VIRTUAL 총 2가지 버전으로 나뉜다.
(참고로 PostgreSQL에서는 STORED 버전만 지원한다)

그래서 어떻게 만들지?

ALTER TABLE products
    ADD COLUMN total_sale BIGINT
        GENERATED ALWAYS AS (price * count) STORED

정의하는 것도 간단하다.
GENERATED ALWAYS AS 뒤에 다른 컬럼의 연산 표현식을 써주면 된다.

 

vs. 기본값을 가지는 컬럼

기본값이 붙는 컬럼은 레코드 생성시에만 값이 채워지고 그 뒤 업데이트가 없지만,
generated column은 인자를 구성하는 컬럼의 값이 변경되면 함께 업데이트 된다.

또 기본값이 붙는 컬럼과 달리,
generated column은 현재 시각 혹은 random()과 같은 volatile function을 사용하지 못한다.
(generated column은 같은 입력값에 대해 동일한 결과를 가져야 하므로)

 

 

3. prisma에서 generated column 사용

0. prisma client에서 사용하지 않을 때

model Product {
  ...
  totalSale BigInt? @ignore
  ...
}

우선은 스키마 파일에서 해당하는 테이블에 컬럼을 추가한다.
만약 prisma client가 사용하지 않도록 하고 싶다면 @ignore를 붙이면 된다.

prisma migrate dev --create-only --name create_column_total_sale

그리고 위 명령어를 통해 마이그레이션 파일을 생성한다.
(아니면 그냥 직접 폴더, 파일을 생성해도 된다)

ALTER TABLE products
    ADD COLUMN total_sale BIGINT
        GENERATED ALWAYS AS (price * count) STORED

prisma client가 자동으로 생성해준 내용은 지우고
위와 같이 generated column을 정의하는 sql을 작성하면 된다.

 

1. prisma client에서 사용하고 싶을 때

model Product {
  ...
  totalSale BigInt @default(dbgenerated())
  ...
}

위와 같이 스키마 파일에서만 @default(dbgenerated())로 정의하면
prisma client로 하여금 해당 컬럼을 감지하고, 코드에서 사용할 수 있게 된다 (참고)

예를 들어 상품마다 총 매출을 보여줘야 한다면
굳이 상품을 들고 와서 totalSale: price * count과 같이 값을 할당할 필요성이 줄어들게 된다.

 

(그래서?)

 

4. 결론

약간의 우여곡절이 있었지만 생각보다 간단하게 구현할 수 있었다.

다만, 이번 주제와는 별개로 BigInt 타입을 JSON.stringify()에 넣을 때 발생하는
에러 문제를 해결해야 한다...

profile
日日是好日

0개의 댓글