logo
Published on

PGTrigger 를 사용하는 법 (공식문서 번역)

Authors

본 문서는 pg-trigger 를 왜 사용하는지 이해하기 위해 pg-trigger documentation 중 도입부를 정리한 것입니다.

What is the PgTrigger

Python pg-trigger package 는 기본적으로 PostgreSQL Trigger 기능 사용을 Django models 에 잘 사용할 수 있도록 돕는 용도로 만들어 진 듯 하다.

왜 triggers 를 사용해야 하는가?

RDB 에서의 trigger 는 일반적인 app 의 코드에 비하여 다양한 복잡한 문제들을 믿을만한, 성능상 문제가 없는, 간결한 방법으로 해결해준다. 아래의 예시를 살펴보자.

  • 행, 열 에서 발생하는 동작들을 보호한다.
  • 읽기전용 모델이나 필드를 생성한다.
  • 모델의 Soft deleting 을 지원한다.
  • 모델의 변경사항을 스냅샷 화 하거나 추적한다.
  • 필드의 변이를 강제한다. - pgtrigger.FSM (무슨 의미인지 추후 파악할 예정)
  • 전문 검색을 위해 검색 벡터 변경사항을 보관한다.
  • 공식 인터페이스를 생성한다. (create, create_user ...)
  • 모델 버저닝, 미러링 필드, 고유 모델 해시 연산(computing unique model hash) 등 다양한 기능

본 문서에서 다룰 기능

PgTrigger 공식문서 의 모든 내용을 다루기는 어려울 것이다. 아래의 기준으로 선정해 다루겠다.

  1. 자주 사용될 만한 기능
  2. 핵심 개념
  3. 유용하게 활용될 수 있는 기능
  4. 유의사항

기초

Trigger 해부하기

Postgres Trigger 는 이벤트와 조건을 기반으로 실행되는 데이터베이스 기능이다. PL/pgSQL 로 작성되었다.

pgtrigger.Trigger 객체는 django-pgtrigger 모든 trigger 의 기본 클래스 이다. 또한 이것은 postgres 의 trigger 를 반영한다. 보통 우리가 사용하게 되는 일반적인 요소는 아래와 같다.

  • name
    • trigger 의 name 을 지칭자. 모든 models 에 통틀어 unique 해야 하며 48자 이하여야 한다.
  • operation
    • trigger 를 작동시키는 table 의 동작이다.
    • Operations
      • pgtrigger.Update
      • pgtrigger.Insert
      • pgtrigger.Delete
      • pgtrigger.Truncate
      • pgtrigger.UpdateOf
    • combinations of triggers (pgtrigger.Insert | pgtrigger.Update) 로 or 처리될 수 있다.
    • Note1. pgtrigger.UpdateOf 는 Update 구문에서 컬럼이 등장할 경우 실행된다. 하지만 다른 트리거가 update 를 하게 된다면 실행되지 않을 수 있다.
    • Note2. 몇몇 조건은 combine 할 수 없다. 예를들어 pgtrigger.UpdateOf 는 다른 operations 와 combine 할 수 없다.
  • when
    • 트리거가 operation 에 의해 (in relation)가지면서 실행되어야 한다.
    • pgtrigger.Before 는 트리거 실행 전 실행된다.
    • 반면에 pgtrigger.After, pgtrigger.InsteadOf 는 SQL view 를 위해 실행된다.
    • Note1. pgtrigger.Before 와 pgtrigger.After 는 특정 상황에서만 SQL view 에서 사용될 수 있다.
  • condition
    • 조건적으로 (조건에 의해) 트리거가 실행된다. OLD, NEW 에 기반해서
    • OLD, NEW 행과 함께 WHERE 절을 구성하기 위해 pgtrigger.Q, pgtrigger.F 를 사용한다.
    • conditional trigger section 에서 자세히 살펴보자
    • Note1. 조건문을 작성할 때에는 OLD and NEW 행에 더 익숙해져야 한다. pgtrigger function. EX: pgtrigger.Insert trigger 에서는 OLD 는 항상 NULL 이다.
  • func
    • 실행할 PL/pgSQL 을 직접 작성할 수 있다.
  • declare (optional)
    • 추가로 변수를 정의할 수 있다. (list of variable_name, variable_type) tuples)
    • ex: declares=[('my_var_1', 'BOOLEAN'), ('my_var_2', 'JSONB')]
  • level
    • 전체 행(pgtrigger.Row) 혹은 전체 상태(pgtrigger.Statement) 를 대상으로 한번 실행할 트리거를 설정한다.
  • referencing
    • statement-level trigger 에서 table transition 으로서 OLD, NEW 행을 참조 한다.
    • EX: pgtrigger.Referencing(old='old_table_name', new='new_table_name') 은 'old_table_name' table 을 생성하고 'new_table_name' table 을 transition table 가능하게 한다.
      ou know how there are OLD and NEW record-variables for FOR EACH ROW triggers?
      
      Transition tables are the FOR EACH STATEMENT equivalents. They're tables with the old and new tuples, so your triggers can see what changed.
      
    • Stack Exchange link in public docs
    • Example
  • timing
    • 유예 가능한(deferrable) CONSTRAINT 트리거를 생성한다. 구문 의 끝부분에서 트리거를 실행하기 위해 pgtrigger.Immediate 를 이용하고, 트랜잭션의 마지막에 실행하기 위해 pgtrigger.Deferred 를 사용한다.
    • Note1. Defferable trigger 는 반드시 pgtrigger.Row 에 level 이 작성되어야 하고 pgtrigger.After 엔 when 이 작성되어야 한다.

Triggers 를 정의하고 설치하기

from django.db import models
import pgtrigger


class CannotDelete(models.Model):
    class Meta:
        triggers = [
            pgtrigger.Protect(name='protect_deletes', operation=pgtrigger.Delete)
        ]

Model method 와 Django signal 을 통해 사용 시 장점

Django signal 내 정의된 로직에 Trigger 를 사용하게 되면, 3가지 주요 장점이 있다.

신뢰성

Python code 와는 달리, 트리거는 어떤 정보 유실도 방지하기 위해 (ensuring that nothing falls through the cracks) DB 에서 쿼리와 함께 실행된다. 반면에 시그널, 모델 메소드는 보안상 불확실성을 제공할 수 있다. 예를 들면 시그널은 bulk_create 를 실행하ㄷ지 않고, data migration 시 custom model method 도 실행되지 않는다. ORM 을 바이패스 하는 서드파티 앱이 또한 불확실하다.

유연성

트리거가 지원할 수 있는 동일한 로직을 완수하는데 모델, managers, querysets을 override 하려 하면 복잡성이 더 커질 수 있다. 비교적 심플한 방법인 조건절을 통한 수행 또한 필드가 바뀌게 되면 이를 명확하게 인지하고 실행하기 어렵다. (Race condition 을 방어하기 어려움. 그리서 trigger 를 쓰는게 좋다는 내용)

Race condition

성능

트리거는 비싼 우회 없이 DB 에 SQL 쿼리를 실행할 수 있다. 이것은 history tracking 이나 데이터 정규화 등에 주요한 성능 상승 요인이 된다.