web-dev-qa-db-ja.com

PostgreSqlのテーブル継承はこの状況に適していますか?

まず、PSQLは初めてで、MSSQLの出身です。 PSQLでDBを設計し始めています。

したがって、私の主な目的は、特定のサービスを制御するために使用するこのスキーマにメインスキーマを配置し、これに複数のスキーマをリンクさせることです。これは、さまざまなクライアントデータになります。

テーブルの継承について説明しましたが、継承を使用してDB移行と同様の効果を持つ人に出会ったことはありません。私が達成したいのは、基本的にデフォルトのスキーマを持ち、クライアントのスキーマはすべてデフォルトから継承することです。これにより、単一のスキーマを変更するだけで、すべてのスキーマのオブジェクトの作成/削除/変更を制御できます。

これは実行可能でしょうか?他の誰かが同様のことをした経験はありますか?誰か提案はありますか?

[〜#〜]更新[〜#〜]

これは私がやったことです。しかし、以下のコードを見ると、スキーマ 'client1'だけで十分だという印象を受けましたが、私は間違っていました。 :D

とにかく、以下は私が実行したスクリプトです。これは、今必要なすべてのことを処理するはずです。ここでは、「client2」スキーマのスクリプトを使用します。良いまたは悪い?

-- public schema --
CREATE TABLE public.Users (
   Id bigserial primary key,
   Login text unique,
   check (false) NO INHERIT 
);

CREATE TABLE public.Roles (
   Id bigserial primary key,
   RoleName text unique,
   check (false) NO INHERIT 
);

CREATE TABLE public.UserRoles (
   Id bigserial primary key,
   UserId bigint references users(id),
   RoleId bigint references roles(id),
   unique (UserId, RoleId),
   check (false) NO INHERIT 
);


-- client1 schema --
CREATE TABLE client1.Users (
)
INHERITS(public.Users);

CREATE TABLE client1.Roles (
)
INHERITS(public.Roles);

CREATE TABLE client1.UserRoles (
)
INHERITS(public.UserRoles);


-- client2 schema --
CREATE TABLE client2.Users (
  primary key (id),
  Unique (Login)
)
INHERITS(public.Users);

CREATE TABLE client2.Roles (
  primary key (id),
  Unique (RoleName)
)
INHERITS(public.Roles);

CREATE TABLE client2.UserRoles (
  primary key (id),
  foreign key (UserId) REFERENCES client2.Users(id),
  foreign key (RoleId) REFERENCES client2.Roles(id),
  unique (UserId, RoleId)
)
INHERITS(public.UserRoles);
6
Lee337

キーとインデックスは各子テーブルで宣言する必要があることに注意してください。

実際、これはテーブル継承の理想的な用途にかなり近いです。注意点に精通し、ユーザースキーマでの外部キーの作成に細心の注意を払うようにしてください。

ただし、CREATEステートメントをすべてのスキーマにカスケードすることはできません。これはスクリプト化する必要があります。ただし、これを行うためにplpgsql関数を作成できます。このようなステートメントは通常パラメーター化されていないため、必要に応じてquote_ident()およびquote_literalを使用する必要があることに注意してください。

リクエストごとにここに例があります。マスタースキーマ内。ここでのキーと一意の制約は、文書化のみを目的としています。

CREATE SCHEMA master;
SET SEARCH_PATH="master;

CREATE TABLE users (
   id bigserial not null unique,
   login text primary key,
   check (false) NO INHERIT -- 9.2 ONLY, prevents any rows in this table
);

CREATE TABLE roles (
   id bigserial not null unique,
   role_name text primary key,
   check (false) NO INHERIT -- 9.2 ONLY, prevents any rows in this table
);

CREATE TABLE user_roles (
   user_id bigint references users(id),
   role_id bigint references roles(id),
   primary key (user_id, role_id)
   check (false) NO INHERIT -- 9.2 ONLY, prevents any rows in this table
);

RESET SEARCH_PATH;

当然、PostgreSQL 9.2にない場合は、チェック制約を削除します。これは、それらが以前のバージョンで継承され、テーブルに行を含めることができないためです。

次に、子スキーマで:

CREATE SCHEMA customer123;
SET SEARCH_PATH 'customer123';

CREATE TABLE users(unique (id), primary key(login)) INHERITS (master.users);
CREATE TABLE roles(unique (id), prikary key(role_name)) INHERITS (master.roles);
CREATE TABLE user_roles(
     foreign key users_id REFERENCES customer123.users(id),
     foreign key role_id REFERENCES customer123.roles(id),
     primary key (users_id, role_id)
);
RESET SEARCH_PATH; 

この場合、マスタースキーマへのアクセスを慎重に制御する必要があることに注意してください。

SELECT tableoid, login from master.users;

すべてのテナントのすべてのユーザーアカウントと、それがどのテナントかを判断するための十分な情報を提供します。

3
Chris Travers

これが実際の経験です。

私はこのような構造を持つ非常に大規模なデータベースに取り組んでいました。当時、私はこの記事に基づいて「マルチテナントスキーマ分離アーキテクチャ」を使用することを決めました: https://msdn.Microsoft.com/en-us/library/aa479086.aspx

この設計をpostgresで使用することを検討している場合は、次のことを考慮してください。

  1. 同じタイプの継承されたすべてのテーブルの同期を維持する管理スクリプトを作成する必要があります(たとえば、client1.user client2.user)また、すべてのテーブルを使用して新しいクライアントスキーマを作成できます。これには、インデックス、外部キー、および継承されず、個別に変更できるその他のものが含まれます。
  2. 自動インクリメントシーケンスは、パブリックスキーマで手動で定義する必要があり、継承されるすべてのテーブルは、スキーマからフィードするために手動で定義する必要があります。
  3. 継承されたすべてのテーブルでパブリックテーブルSELECTを実行していて、クライアントスキーマが少ない場合のパフォーマンスの問題。これはマテリアライズドビューを使用して解決できますが、継続的に更新することはできないため、これは実際の問題です。

データベースがほとんどすべての継承テーブルでパブリックテーブルSELECTsを実行している場合は、この設計を使用しないでください。すべてのスキーマを実行し、共有テーブルを使用する場合と比較して大きなオーバーヘッドが追加されるためです。ソフトウェアが主にクライアントスキーマ内でクエリを実行している場合(または CHECKフィルター条件 を使用してパブリックで)、パブリックSELECTsがバッチ/低頻度の操作専用である場合は、問題ありません。

1
roman-io