PostgreSQL에서 상속 된 테이블을 언제 사용합니까?


84

어떤 상황에서 상속 된 테이블을 사용해야합니까? 나는 그것들을 아주 짧게 사용하려고했고 상속은 OOP 세계 에서처럼 보이지 않았습니다.

다음과 같이 작동한다고 생각했습니다.

users모든 사용자 레벨에 필요한 모든 필드가있는 테이블 . 테이블 좋아 moderators, admins, bloggers, 등하지만 필드가되어 있지 부모로부터 확인. 예를 들어 users이메일 필드가 상속 bloggers도 지금 가지고 있지만 모두 고유 아니에요 usersbloggers동시에. 즉. 두 테이블에 이메일 필드를 추가하는 것과 동일합니다.

내가 생각할 수있는 유일한 사용법은 row_is_deleted , created_at , modified_at 와 같이 일반적으로 사용되는 필드입니다 . 상속 된 테이블에 대한 유일한 사용법입니까?

답변:


111

postgres에서 테이블 상속을 사용하는 몇 가지 주요 이유가 있습니다.

매월 생성되고 채워지는 통계에 필요한 몇 가지 테이블이 있다고 가정 해 보겠습니다.

statistics
    - statistics_2010_04 (inherits statistics)
    - statistics_2010_05 (inherits statistics)

이 샘플에서는 각 테이블에 2.000.000 개의 행이 있습니다. 각 테이블에는 일치하는 월의 데이터 만 저장되도록하는 CHECK 제약 조건이 있습니다.

그렇다면 상속을 멋진 기능으로 만드는 것은 무엇입니까? 데이터를 분할하는 것이 멋진 이유는 무엇입니까?

  • 성능 : 데이터를 선택할 때 x와 Y 사이의 날짜에서 * 통계를 선택하고 Postgres는 테이블 만 사용합니다. 예 : SELECT * FROM statistics WHERE date BETWEEN '2010-04-01'및 '2010-04-15'는 statistics_2010_04 테이블 만 스캔하며 다른 모든 테이블은 처리되지 않습니다.
  • 인덱스 크기 : 날짜 열에 큰 팻 인덱스가있는 큰 팻 테이블이 없습니다. 우리는 매월 작은 인덱스를 가진 작은 테이블을 가지고 있습니다-더 빠른 읽기.
  • 유지 관리 : 다른 모든 데이터를 잠그지 않고 매달 테이블에서 vacuum full, reindex, cluster를 실행할 수 있습니다.

성능 향상을 위해 테이블 ​​상속을 올바르게 사용하려면 postgresql 매뉴얼을 참조하십시오. 데이터베이스에 데이터가 분할 (파티션)되는 키를 알리려면 각 테이블에 CHECK 제약 조건을 설정해야합니다.

특히 월별로 그룹화 된 로그 데이터를 저장할 때 테이블 상속을 많이 사용합니다. 힌트 : 변경되지 않는 데이터 (로그 데이터)를 저장하는 경우 CREATE INDEX ON () WITH (fillfactor = 100); 이는 업데이트를위한 공간이 인덱스에 예약되지 않음을 의미합니다. 인덱스는 디스크에서 더 작습니다.

업데이트 : fillfactor 기본값은 http://www.postgresql.org/docs/9.1/static/sql-createtable.html 에서 100입니다 .

테이블의 채우기 비율은 10에서 100 사이의 백분율입니다. 100 (완전 패킹)이 기본값입니다.


13
파티셔닝의 또 다른 예
프랭크 Heikens

4
항목 1에서 Postgres는 검색에 필요한 테이블을 어떻게 이해합니까? 상위 테이블에서 선택하고 날짜 범위는 분할의 편리한 예일뿐입니다. 부모 테이블은이 논리를 알 수 없습니다. 아니면 내가 틀렸어?
Alexander Palamarchuk 2012 년

4
상위 테이블에 대한 쿼리를 수행하는 것은 공통 행의 모든 ​​하위 테이블에 대해 UNION ALL에 대한 쿼리를 수행하는 것과 사실상 동일합니다. 쿼리 플래너는 각 파티션을 정의하는 검사 제약 조건을 알고 있으며 파티션이 겹치지 않는 한이를 사용하여 CHECK가 반환되는 행이 없음을 나타내는 테이블 검사를 건너 뛸 수 있는지 여부를 결정합니다. 이것에 대한 Postgres 문서
zxq9 2013

@avesus heh ... 위의 코드는 그 자체로 그런 풍자에 걸 맞습니다. 이런 종류의 일을 일종의 유지 관리 루틴으로 묶는 것이 일반적입니다. 이것은 어떤 조건, 크론 작업 등에서 그것을 처리하는 저장 프로시 저만큼 간단 할 수 있습니다. 날짜별로 파티션을 나누는 것이 일반적이지만 가끔 테이블 스페이스 할당에 따라 파티션을 나누는 경우도 있으며 외부 정보가 필요합니다. 파티션 베이비 시터를 작성하는 데 걸리는 30 분은 제어 할 가치가 있습니다. 그것은 당신에게 제공합니다.
zxq9

흠. 차단되지 않는 것이 확실합니까? 비슷한 설정이 있지만 단일 파티션에서 CLUSTER 명령을 실행하면 다른 파티션 블록이 보유한 데이터에 대한 SELECT 문!
E. van Putten

37

"테이블 상속" "클래스 상속"과 다른 것을 의미 하며 다른 용도로 사용됩니다.

Postgres는 데이터 정의에 관한 것입니다. 때때로 정말 복잡한 데이터 정의. OOP (일반적인 Java 색상 의미에서)는 단일 원자 구조의 데이터 정의에 동작을 종속시키는 것입니다. 여기서 "상속"이라는 단어의 목적과 의미는 크게 다릅니다.

OOP 영역에서 정의 할 수 있습니다 (여기서 구문과 의미론이 매우 느슨 함).

import life

class Animal(life.Autonomous):
  metabolism = biofunc(alive=True)

  def die(self):
    self.metabolism = False

class Mammal(Animal):
  hair_color = color(foo=bar)

  def gray(self, mate):
    self.hair_color = age_effect('hair', self.age)

class Human(Mammal):
  alcoholic = vice_boolean(baz=balls)

이에 대한 표는 다음과 같습니다.

CREATE TABLE animal
  (name       varchar(20) PRIMARY KEY,
   metabolism boolean NOT NULL);

CREATE TABLE mammal
  (hair_color  varchar(20) REFERENCES hair_color(code) NOT NULL,
   PRIMARY KEY (name))
  INHERITS (animal);

CREATE TABLE human
  (alcoholic  boolean NOT NULL,
   FOREIGN KEY (hair_color) REFERENCES hair_color(code),
   PRIMARY KEY (name))
  INHERITS (mammal);

그러나 행동은 어디에 있습니까? 그들은 어디에도 맞지 않습니다. 데이터베이스는 절차 적 코드가 아니라 데이터와 관련되기 때문에 이것은 데이터베이스 세계에서 논의되는 "객체"의 목적이 아닙니다. 계산을 수행하기 위해 데이터베이스에 함수를 작성할 수 있지만 (종종 아주 좋은 생각이지만이 경우에 맞는 것은 아닙니다) 함수는 메서드와 동일하지 않습니다. 즉, 말하는 OOP의 형태로 이해되는 메서드입니다. 의도적으로 유연성이 떨어집니다.

계통도 장치로서 상속에 대해 지적해야 할 사항이 한 가지 더 있습니다. Postgres 9.2부터는 모든 파티션 / 테이블 패밀리 구성원에 대해 한 번에 외래 키 제약 조건을 참조 할 수있는 방법이 없습니다. 이를 수행하기 위해 검사를 작성하거나 다른 방법으로 해결할 수 있지만 기본 제공 기능은 아닙니다 (실제로는 복잡한 인덱싱 문제로 귀결되며 아무도 자동으로 만드는 데 필요한 비트를 작성하지 않았습니다). 이러한 목적으로 테이블 상속을 사용하는 대신 개체 상속을 위해 데이터베이스에서 더 나은 일치는 테이블에 대한 도식 확장을 만드는 것입니다. 이 같은:

CREATE TABLE animal
  (name       varchar(20) PRIMARY KEY,
   ilk        varchar(20) REFERENCES animal_ilk NOT NULL,
   metabolism boolean NOT NULL);

CREATE TABLE mammal
  (animal      varchar(20) REFERENCES animal PRIMARY KEY,
   ilk         varchar(20) REFERENCES mammal_ilk NOT NULL,
   hair_color  varchar(20) REFERENCES hair_color(code) NOT NULL);


CREATE TABLE human
  (mammal     varchar(20) REFERENCES mammal PRIMARY KEY,
   alcoholic  boolean NOT NULL);

이제 외래 키 참조로 안정적으로 사용할 수있는 동물의 인스턴스에 대한 표준 참조가 있고 확장 데이터의 "다음"테이블을 가리키는 xxx_ilk 정의 테이블을 참조하는 "ilk"열이 있습니다 ( 또는 ilk가 제네릭 유형 자체 인 경우 없음을 나타냅니다.) 이러한 종류의 스키마에 대해 테이블 ​​함수, 뷰 등을 작성하는 것은 매우 쉬워서 대부분의 ORM 프레임 워크는 OOP 스타일 클래스 상속에 의존하여 개체 유형의 패밀리를 생성 할 때 백그라운드에서 이러한 종류의 작업을 정확하게 수행합니다.


알려진 모든 포유류를 추가한다면 어떨까요? 포유류로부터 물려 받으시겠습니까, 아니면 여기서했던 것처럼 외래 키를 가지고 계십니까? 외래 키에 대한 문제는 결국 너무 많은 조인을 수행해야한다는 것입니다.
puk

1
@puk 먼저 알려진 모든 포유류를 추가하는 이유 를 결정해야합니다 . 데이터의 형태는 데이터가 사용되는 방식에 따라 결정될 것입니다 (이 경우 동물 당 테이블을 가질 필요는 없을 것입니다. 실제로 모든 유형의 몹이있는 게임 최고의 데이터베이스를 고려하십시오.) ). 위의 경우 mammal JOIN human매번 조인을 작성하는 것이 짜증나 기 때문에 일반적으로 가장 일반적인 경우 인 뷰를 추가합니다 . 그러나 조인을 피하지 마십시오 . 조인은 RDBMS에 R을 넣는 것입니다. 조인이 마음에 들지 않으면 다른 db 유형을 사용해야합니다.
zxq9

@ zxq9 : 큰 테이블로 인한 거대하고 비효율적 인 조인이 구체화 된 뷰가 작동하는 곳이라고 생각합니다. (나는 오랫동안 포스트 그레스를 사용하지했습니다)
마크 K 코완

1
@MarkKCowan 조인은 비효율적이지 않습니다. 비효율적 인 것은 엉성한 디자인으로 인해 인덱싱되지 않고 고유하지 않은 필드에 조인하려고하는 것입니다 (스키마가 정규화에 가깝지 않기 때문에). 이러한 경우 구체화 된 뷰가 도움이 될 수 있습니다. 구체화 된 뷰는 도식 기반으로 정규화 된 데이터가 필요한 경우에도 유용하지만 (종종 사실임) 처리 효율성 (계산 초기 부하) 또는인지 효율성을 위해 더 쉽게 작업 할 수있는 비정규 화 된 여러 표현이 필요한 경우에도 유용합니다. 그러나 읽는 것보다 더 많이 쓰면 비관적입니다.
zxq9

1
@MarkKCowan "Slow"는 상대적인 용어입니다. 쿼리를 반환하는 데 최대 50ms를 허용 할 수있는 대규모 비즈니스 시스템 및 게임 서버에서 20 개의 테이블 조인은 내 경험에서 문제가되지 않았습니다 (Postgres 8 이상에서는 어쨌든). 그러나 경영진이 인덱싱되지 않은 데이터 (또는 파생 된 값!)에 대해 5 개 이상의 테이블에서 10b 개 이상의 행 조인에 대해 1ms 미만의 응답을 원하는 경우 ...이 조인을 지난달에 만들고 숨긴 것 외에는 "빠른"느낌이없는 시스템은 없습니다. 빠른 K / V 스토어 (본질적으로 구체화 된 뷰가 특수한 상황에서 작동 할 수있는 것임) 쓰기 또는 읽기 시간에 트레이드 오프를 벗어날 수 없습니다.
zxq9

6

상위 테이블에서 외래 키를 만들 필요가없는 한 상속은 OOP 패러다임에서 사용할 수 있습니다. 예를 들어, 차량 테이블에 저장된 추상 클래스 차량과이를 상속하는 테이블 차량이있는 경우 모든 차량이 차량 테이블에 표시되지만 차량 테이블의 운전자 테이블에있는 외래 키는이 테이블과 일치하지 않습니다. 기록.

상속은 분할 도구 로도 사용할 수 있습니다 . 이것은 영원히 성장할 테이블 (로그 테이블 등)이있을 때 특히 유용합니다.


1
테이블 제약 조건은 상속되지 않으므로 외래 키 이상입니다. DDL에서 생성 된 하위 테이블에 테이블 제약 조건을 적용하거나 동일한 제약 조건에 영향을주는 트리거를 작성할 수 있습니다.
Wexxor

3

상속의 주요 용도는 분할에 사용되지만 때로는 다른 상황에서 유용합니다. 내 데이터베이스에는 외래 키만 다른 많은 테이블이 있습니다. 내 "추상 클래스"테이블 "이미지"에는 "ID"(모든 테이블에 기본 키가 있어야 함)와 PostGIS 2.0 래스터가 있습니다. "site_map"또는 "artifact_drawing"과 같은 상속 된 테이블에는 외래 키 열 ( "site_map"의 경우 "site_name"텍스트 열, "artifact_drawing"테이블의 경우 "artifact_id"정수 열 등) 및 기본 및 외래 키 제약 조건이 있습니다. 나머지는 "이미지"테이블에서 상속됩니다. 앞으로 모든 이미지 테이블에 "설명"열을 추가해야 할 수도 있으므로 실제 문제를 만들지 않고도 많은 작업을 절약 할 수 있습니다.

편집 : 또 다른 좋은 사용 : 등록되지 않은 사용자를 두 테이블로 처리하면 다른 RDBMS가 두 테이블을 처리하는 데 문제가 있지만 PostgreSQL에서는 쉽습니다 ONLY. 상속 된 "등록되지 않은 사용자"테이블의 데이터에 개입하지 않을 때 추가하기 만하면 됩니다.


2

상속 된 테이블에 대한 유일한 경험은 파티셔닝입니다. 잘 작동하지만 PostgreSQL에서 가장 정교하고 사용하기 쉬운 부분은 아닙니다.

지난주에 우리는 동일한 OOP 문제를보고 있었지만 Hibernate에 너무 많은 문제가 있었기 때문에 (설정이 마음에 들지 않았습니다) PostgreSQL에서 상속을 사용하지 않았습니다.


0

테이블 사이에 일대일 관계가 더 많을 때 상속을 사용합니다.

예 : x, y, 회전, 축척 속성이있는 객체 맵 위치를 저장한다고 가정합니다.

이제지도에 표시 할 여러 종류의 객체가 있고 각 객체에 자체지도 위치 매개 변수가 있고지도 매개 변수는 재사용되지 않는다고 가정합니다.

이러한 경우 테이블 상속은 비정규 화 된 테이블을 유지하거나 위치 ID를 생성하고 다른 테이블에 대한 상호 참조를 피하는 데 매우 유용합니다.


-4

가능한 한 적게 사용하십시오. 그리고 그것은 일반적으로 결코 의미가 없습니다. 예를 들어 정보 원칙을 깨고 관계 대신 가방을 만들어 관계형 모델을 위반하는 구조를 만드는 방식으로 끓어 오릅니다.

대신 추가 정규 형식을 포함하여 적절한 관계형 모델링과 결합 된 테이블 분할을 사용하십시오.


4
PostgreSQL의 상속 기능이 정보 원칙을 위반하여 관계형 모델을 위반하는 것은 사실이 아닙니다. 정보 원리는 관계형 데이터베이스의 모든 데이터가 관계의 데이터 값으로 표현되며, 모든 쿼리 결과를 다시 관계로 표현되는 것을 말한다. ( en.wikipedia.org/wiki/Relational_model가 )이 사건은 모든 테이블 때문에, 항상 다른 테이블을 상속하는은 다시 간단한 테이블입니다. 그렇기 때문에 그것이 의미하는 바가 무엇이든 "가방"과 같은 것도 없습니다.
롤랜드

2
글쎄요, 위키피디아는 관계형 모델과 관련하여 거의 참조가 아닙니다. SQL이 관계형 모델을 위반하는 것을 인식하는 것을 거부합니다. bag은 잠재적으로 중복이 있으므로 관계가 아니므로 키가없는 테이블입니다. 관계는 집합이어야합니다.
Leandro

이는 기능 자체의 문제가 아니라 사용 방법입니다. uuid를 식별자로 사용하는 경우 모든 하위 테이블에 대해 고유 한 키를 갖게됩니다.
Roland

요점이 있지만 여기서 문제는 상속으로 인해 모델러가 관계형 모델을 무시하게된다는 것입니다. UUID는 실제 키가 아니라 대리 키입니다. 여전히 자연 키를 선언해야합니다.
Leandro
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.