アイテムのテーブルがあると仮定しましょう:
CREATE TABLE items
(
item serial PRIMARY KEY,
...
);
次に、各アイテムの「アクセス許可」の概念を紹介します(ここでは、データベースアクセス許可についてではなく、そのアイテムのビジネスロジック許可について説明していることに注意してください)。各アイテムにはデフォルトの許可があり、デフォルトの許可よりも優先されるユーザーごとの許可もあります。
私はこれを実装するいくつかの方法を考えて、次の解決策を考え出しましたが、どれが最良であり、なぜかについてはわかりません。
1)ブール解
各権限にブール列を使用します。
CREATE TABLE items
(
item serial PRIMARY KEY,
can_change_description boolean NOT NULL,
can_change_price boolean NOT NULL,
can_delete_item_from_store boolean NOT NULL,
...
);
CREATE TABLE item_per_user_permissions
(
item int NOT NULL REFERENCES items(item),
user int NOT NULL REFERENCES users(user),
PRIMARY KEY(item, user),
can_change_description boolean NOT NULL,
can_change_price boolean NOT NULL,
can_delete_item_from_store boolean NOT NULL,
...
);
利点:各許可には名前が付けられます。
短所:列の数を大幅に増やす許可が多数あり、それらを2回定義する必要があります(各テーブルで1回)。
2)整数ソリューション
整数を使用し、ビットフィールドとして扱います(つまり、ビット0はfor can_change_description
、ビット1はforなどcan_change_price
、ビット単位の操作を使用してアクセス許可を設定または読み取ります)。
CREATE DOMAIN permissions AS integer;
利点:非常に高速。
短所:データベースとフロントエンドインターフェイスの両方で、どのビットがどの許可を表しているかを追跡する必要があります。
3)ビットフィールドソリューション
2)と同じbit(n)
ですが、を使用します。ほとんどの場合、同じ長所と短所がありますが、少し遅いかもしれません。
4)列挙ソリューション
許可に列挙型を使用します。
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
次に、デフォルトの許可用に追加のテーブルを作成します。
CREATE TABLE item_default_permissions
(
item int NOT NULL REFERENCES items(item),
perm permission NOT NULL,
PRIMARY KEY(item, perm)
);
ユーザーごとの定義テーブルを次のように変更します。
CREATE TABLE item_per_user_permissions
(
item int NOT NULL REFERENCES items(item),
user int NOT NULL REFERENCES users(user),
perm permission NOT NULL,
PRIMARY KEY(item, user, perm)
);
利点:個々のアクセス許可に名前を付けるのは簡単です(ビット位置を処理する必要はありません)。
短所:デフォルトのアクセス許可を取得するだけでも、2つの追加テーブルにアクセスする必要があります。1つ目はデフォルトのアクセス許可テーブル、2つ目は列挙値を格納するシステムカタログです。
特に、そのアイテムのすべての単一ページビューについてデフォルトのアクセス許可を取得する必要があるため、最後の選択肢のパフォーマンスへの影響が大きい可能性があります。
5)列挙配列ソリューション
4)と同じですが、配列を使用してすべての(既定の)アクセス許可を保持します。
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
CREATE TABLE items
(
item serial PRIMARY KEY,
granted_permissions permission ARRAY,
...
);
利点:個々のアクセス許可に名前を付けるのは簡単です(ビット位置を処理する必要はありません)。
短所:第1正規形を壊し、少しいです。許可の数が大きい場合(約50)、大量のバイトを連続して使用します。
他の選択肢を考えられますか?
どのアプローチを採用する必要があり、その理由は何ですか?
注:これは、以前にStackoverflowに投稿された質問の修正版です。
bigint
フィールド(それぞれが64ビットに適している)またはビット文字列を選択する場合があります。SOに関連する回答をいくつか