PostgreSQLで継承されたテーブルを使用するのはいつですか?


84

継承されたテーブルを使用する必要があるのはどのような状況ですか?私はそれらを非常に簡単に使用しようとしましたが、継承はOOPの世界では見られませんでした。

私はそれがこのように機能すると思いました:

usersすべてのユーザーレベルに必要なすべてのフィールドを含むテーブル。以下のようなテーブルmoderatorsadminsbloggersなどが、フィールドがされていない親からチェックします。たとえば、usersメールフィールドがあり、継承されたbloggersものもありますが、両方で同時に一意ではusersありませんbloggers。すなわち。両方のテーブルにメールフィールドを追加するのと同じです。

私は考えることができる唯一の使用量は、通常のように、使用されている分野であるrow_is_deletedのcreated_atmodified_at。これは継承されたテーブルの唯一の使用法ですか?

回答:


111

postgresでテーブル継承を使用する主な理由はいくつかあります。

たとえば、統計に必要なテーブルがいくつかあり、毎月作成されて入力されます。

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

このサンプルでは、​​各テーブルに2.000.000行があります。各テーブルには、一致する月のデータのみが格納されるようにするためのCHECK制約があります。

では、継承が優れた機能である理由は何ですか?データを分割するのが優れているのはなぜですか?

  • パフォーマンス:データを選択するときは、SELECT * FROM statistics WHERE date BETWEEN x and Yであり、Postgresは意味のあるテーブルのみを使用します。例えば。SELECT * FROM statistics WHERE date BETWEEN '2010-04-01' AND '2010-04-15'は、テーブルstatistics_2010_04のみをスキャンし、他のすべてのテーブルは変更されません-高速です!
  • インデックスサイズ:列の日付に大きなファットインデックスを持つ大きなファットテーブルはありません。月に小さなテーブルがあり、インデックスが小さく、読み取りが高速です。
  • メンテナンス:他のすべてのデータをロックすることなく、毎月のテーブルでバキュームフル、インデックスの再作成、クラスター化を実行できます

パフォーマンスブースターとしてのテーブル継承の正しい使用法については、postgresqlのマニュアルを参照してください。各テーブルにCHECK制約を設定して、データがどのキーで分割(パーティション化)されるかをデータベースに通知する必要があります。

特に月ごとにグループ化されたログデータを格納する場合は、テーブル継承を多用します。ヒント:変更されないデータ(ログデータ)を保存する場合は、CREATE INDEX ON()WITH(fillfactor = 100);を使用して作成またはインデックスを作成します。これは、更新用のスペースがインデックスに予約されないことを意味します。インデックスはディスク上で小さくなります。

更新:fillfactorのデフォルトは100で、http://www.postgresql.org/docs/9.1/static/sql-createtable.htmlから:

テーブルのフィルファクターは10から100の間のパーセンテージです。100(完全なパッキング)がデフォルトです


13
パーティショニングの別の例
Frank Heikens 2010年

4
アイテム1で、Postgresはどのテーブルを検索する必要があるかをどのように理解しますか?親テーブルから選択します。日付範囲は、分割の便利な例にすぎません。親テーブルはこのロジックを知ることができません。または私は間違っていますか?
Alexander Palamarchuk 2012

4
親テーブルでクエリを実行することは、共通行のすべての子孫テーブルでUNIONALLでクエリを実行することと実質的に同じです。クエリプランナーは、各パーティションを定義するチェック制約を認識しており、パーティションがオーバーラップしない限り、それらを使用して、行が返されないことをCHECKが示すテーブルのチェックをスキップできるかどうかを判断します。これに関するPostgresのドキュメント
zxq9 2013

@avesus heh ...上記のコード自体は、そのような皮肉に値します。この種のものをある種のメンテナンスルーチンにまとめるのが一般的です。これは、特定の条件、cronジョブなどで処理するストアドプロシージャと同じくらい簡単です。日付でパーティション化するのが一般的ですが、テーブルスペースの割り当てでパーティション化することも時々あり、外部情報が必要です。パーティションのベビーシッターを作成するのにかかる30分は、制御する価値があります。それはあなたに与えます。
zxq9 2015年

うーん。ブロックしませんか?同様の設定がありますが、単一のパーティションで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の形式で理解されるメソッドです。については意図的に柔軟性が低くなっています。

回路図デバイスとしての継承についてもう1つ指摘することがあります。Postgres9.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がジェネリック型自体の場合は存在しないことを示します)。この種のスキーマに対してテーブル関数やビューなどを作成するのは非常に簡単なので、オブジェクト型のファミリを作成するためにOOPスタイルのクラス継承に頼る場合、ほとんどのORMフレームワークはバックグラウンドでまさにこの種のことを行います。


既知の哺乳類をすべて追加した場合はどうなりますか?哺乳類から受け継いだり、ここで行ったような外部キーを持ったりしますか?私が外部キーに関して抱えている問題は、あなたが非常に多くの結合をしなければならないということです。
puk 2015

1
@puk最初に、既知のすべての哺乳類を追加する理由を決定する必要があります。データの形状は、データの使用方法によって決定されます(この場合、動物ごとにテーブルを用意する必要はおそらくありません。実際にあらゆる種類の暴徒がいるゲームの動物寓話のデータベースを検討してください。 )。上記の場合、mammal JOIN human毎回結合を書き込むのが面倒であるという理由だけで、通常、の最も一般的なケースであるビューを追加します。ただし、結合は避けないでください。結合は、RをRDBMSに配置するものです。結合が気に入らない場合は、別のデータベースタイプを使用する必要があります。
zxq9 2015

@ zxq9:大きなテーブルによる大規模で非効率的な結合が、マテリアライズドビューの出番になると思いますか?(私はPostgresをそれほど長く使用していません)
Mark K Cowan 2016

1
@MarkKCowan結合は非効率的ではありません。非効率的なのは、設計がずさんなために、インデックス付けされていない、一意でないフィールドに結合しようとすることです(スキーマが正規化に近い場所にないため)。そのような場合、マテリアライズドビューが役立ちます。マテリアライズドビューは、スケマティックファンデーションとして正規化されたデータが必要な場合(多くの場合真)にも役立ちますが、処理効率(計算のフロントロード)または認知効率のいずれかのために操作しやすい、いくつかの非正規化表現も必要です。しかし、読む以上に書く場合、それは悲観的です。
zxq9 2016

1
@MarkKCowan「遅い」は相対的な用語です。クエリを返すのに最大50ミリ秒を受け入れることができる大規模なビジネスシステムやゲームサーバーでは、20のテーブル結合が私の経験では(とにかくPostgres 8以降で)問題になることはありませんでした。しかし、管理者がインデックス付けされていないデータ(または派生値!)の5つ以上のテーブルにわたる100億を超える行結合に対して1ミリ秒未満の応答を必要とする場合...先月この結合を行ってそれを隠しておく以外に、世界のどのシステムも「速い」と感じることはありません。高速K / Vストア(これは基本的に、マテリアライズドビューが特別な状況で機能できるものです)。書き込み時または読み取り時のトレードオフを回避することはできません。
zxq9 2016

6

親テーブルに外部キーを作成する必要がない限り、継承はOOPパラダイムで使用できます。たとえば、抽象クラスの車両が車両テーブルに格納されていて、それを継承するテーブルカーがある場合、すべての車両が車両テーブルに表示されますが、車両テーブルのドライバーテーブルからの外部キーはこれらと一致しません。記録。

継承は、パーティショニングツールとしても使用できます。これは、永遠に成長することを意図したテーブル(ログテーブルなど)がある場合に特に役立ちます。


1
テーブル制約は継承されないため、外部キーだけではありません。DDLで作成された子テーブルにテーブル制約を適用することも、同じ制約を実行するトリガーを作成することもできます。
Wexxor 2012

3

継承の主な用途はパーティション分割ですが、他の状況で役立つ場合もあります。私のデータベースには、外部キーだけが異なるテーブルがたくさんあります。私の「抽象クラス」テーブル「画像」には、「ID」(すべてのテーブルに存在する必要がある主キー)とPostGIS2.0ラスターが含まれています。「site_map」や「artifact_drawing」などの継承されたテーブルには、外部キー列(「site_map」の「site_name」テキスト列、「artifact_drawing」テーブルの「artifact_id」整数列など)と主キーおよび外部キーの制約があります。残りは「画像」テーブルから継承されます。将来、すべての画像テーブルに「説明」列を追加する必要があるかもしれないと思うので、これにより、実際の問題を発生させることなく、かなりの作業を節約できる可能性があります(まあ、

編集:別の良い使用法:未登録ユーザーの2つのテーブル処理では、他のRDBMSは2つのテーブルの処理に問題がありますが、PostgreSQLでは簡単です-ONLY継承された「未登録ユーザー」テーブルのデータに関心がない場合に追加するだけです。


2

継承されたテーブルで私が経験した唯一の経験は、分割です。正常に動作しますが、PostgreSQLの中で最も洗練された使いやすい部分ではありません。

先週、同じOOPの問題を探していましたが、Hibernateで問題が多すぎたため(セットアップが気に入らなかった)、PostgreSQLで継承を使用しませんでした。


0

テーブル間に1対1の関係が複数ある場合は、継承を使用します。

例:属性x、y、rotation、scaleを持つオブジェクトマップの場所を保存するとします。

ここで、マップに表示するオブジェクトの種類がいくつかあり、各オブジェクトに独自のマップ位置パラメーターがあり、マップパラメーターが再利用されないとします。

このような場合、テーブルの継承は、正規化されていないテーブルを維持したり、ロケーションIDを作成して他のテーブルと相互参照したりする必要がないようにするために非常に役立ちます。


-4

できるだけ使用しないでください。そして、それは通常決して決して意味しません。たとえば、情報の原則を破ったり、関係の代わりにバッグを作成したりすることによって、リレーショナルモデルに違反する構造を作成する方法に要約されます。

代わりに、さらに通常の形式を含む、適切なリレーショナルモデリングと組み合わせたテーブルパーティショニングを使用してください。


4
PostgreSQLの継承機能が情報の原則を破ることによってリレーショナルモデルに違反しているというのは真実ではありません。情報の原則によると、リレーショナルデータベース内のすべてのデータはリレーション内のデータ値で表され、すべてのクエリ結果は再びリレーションとして表されます。(en.wikipedia.org/wiki/Relational_model)これは常に当てはまります。これは、すべてのテーブルが別のテーブルを継承する、は、やはり単純なテーブルです。そのため、それが何を意味するにせよ、「バッグ」のようなものもありません。
ローランド

2
まあ、ウィキペディアはリレーショナルモデルに関してほとんど参照されていません。SQLがリレーショナルモデルに違反していることを認識することを拒否します。バッグはキーのないテーブルです。重複している可能性があり、関係ではないためです。リレーションはセットである必要があります。
Leandro 2017年

これは機能自体の問題ではなく、その使用方法の問題です。識別子としてuuidを使用する場合、すべてのサブテーブルに一意のキーがあります。
ローランド

あなたにはポイントがありますが、ここでの問題は、継承によってモデラーがリレーショナルモデルを無視するようになることです。UUIDは実際のキーではなく、代理キーです。自然キーを宣言する必要があります。
Leandro
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.