Anggap saya memiliki daftar item:
CREATE TABLE items
(
item serial PRIMARY KEY,
...
);
Sekarang, saya ingin memperkenalkan konsep "izin" untuk setiap item (harap dicatat, saya tidak berbicara tentang izin akses database di sini, tetapi izin logika bisnis untuk item tersebut). Setiap item memiliki izin default dan juga izin per pengguna yang dapat mengesampingkan izin default.
Saya mencoba memikirkan beberapa cara untuk mengimplementasikan ini dan menemukan solusi berikut, tetapi saya tidak yakin yang mana yang terbaik dan mengapa:
1) Solusi Boolean
Gunakan kolom boolean untuk setiap izin:
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,
...
);
Keuntungan : Setiap izin diberi nama.
Kekurangan : Ada puluhan izin yang meningkatkan jumlah kolom secara signifikan dan Anda harus mendefinisikannya dua kali (satu kali di setiap tabel).
2) Solusi Integer
Gunakan integer dan perlakukan sebagai bitfield (yaitu bit 0 untuk can_change_description
, bit 1 untuk can_change_price
, dan sebagainya, dan gunakan operasi bitwise untuk mengatur atau membaca izin).
CREATE DOMAIN permissions AS integer;
Keuntungan : sangat cepat.
Kekurangan : Anda harus melacak bit mana yang menunjukkan izin di database dan antarmuka front-end.
3) Solusi Bitfield
Sama seperti 2), tetapi gunakan bit(n)
. Kemungkinan besar kelebihan dan kekurangan yang sama, mungkin sedikit lebih lambat.
4) Solusi Enum
Gunakan tipe enum untuk izin:
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
lalu buat tabel tambahan untuk izin default:
CREATE TABLE item_default_permissions
(
item int NOT NULL REFERENCES items(item),
perm permission NOT NULL,
PRIMARY KEY(item, perm)
);
dan ubah tabel definisi per pengguna ke:
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)
);
Keuntungan : Mudah menyebutkan izin individu (Anda tidak harus menangani posisi bit).
Kekurangan : Bahkan ketika hanya mengambil izin default, itu memerlukan mengakses dua tabel tambahan: pertama, tabel izin default, dan kedua, katalog sistem menyimpan nilai enum.
Terutama karena izin default harus diambil untuk setiap tampilan halaman dari item itu , dampak kinerja dari alternatif terakhir mungkin signifikan.
5) Solusi Enum Array
Sama seperti 4), tetapi gunakan array untuk menampung semua izin (default):
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
CREATE TABLE items
(
item serial PRIMARY KEY,
granted_permissions permission ARRAY,
...
);
Keuntungan : Mudah menyebutkan izin individu (Anda tidak harus menangani posisi bit).
Kekurangan : Mematahkan bentuk normal pertama dan agak jelek. Mengambil banyak byte dalam satu baris jika jumlah izinnya besar (sekitar 50).
Bisakah Anda memikirkan alternatif lain?
Pendekatan mana yang harus diambil dan mengapa?
Harap dicatat: ini adalah versi modifikasi dari pertanyaan yang diposting sebelumnya di Stackoverflow .
bigint
bidang (masing-masing bagus untuk 64 bit) atau sedikit string. Saya menulis beberapa jawaban terkait pada SO yang mungkin bisa membantu.