Giả sử tôi có một bảng các mặt hàng:
CREATE TABLE items
(
item serial PRIMARY KEY,
...
);
Bây giờ, tôi muốn giới thiệu khái niệm "quyền" cho từng mục (xin lưu ý, tôi không nói về quyền truy cập cơ sở dữ liệu ở đây, nhưng quyền logic kinh doanh cho mục đó). Mỗi mục có quyền mặc định và quyền cho mỗi người dùng có thể ghi đè quyền mặc định.
Tôi đã cố gắng nghĩ ra một số cách để thực hiện điều này và đưa ra các giải pháp sau đây, nhưng tôi không chắc đâu là cách tốt nhất và tại sao:
1) Giải pháp Boolean
Sử dụng cột boolean cho mỗi quyền:
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,
...
);
Ưu điểm : Mỗi quyền được đặt tên.
Nhược điểm : Có hàng tá quyền làm tăng đáng kể số lượng cột và bạn phải xác định chúng hai lần (một lần trong mỗi bảng).
2) Giải pháp số nguyên
Sử dụng một số nguyên và coi nó như một bitfield (nghĩa là bit 0 dành cho can_change_description
, bit 1 là dành cho can_change_price
, v.v. và sử dụng các thao tác bitwise để đặt hoặc đọc quyền).
CREATE DOMAIN permissions AS integer;
Ưu điểm : rất nhanh.
Nhược điểm : Bạn phải theo dõi bit nào đại diện cho quyền nào trong cả cơ sở dữ liệu và giao diện mặt trước.
3) Giải pháp Bitfield
Tương tự như 2), nhưng sử dụng bit(n)
. Rất có thể là những lợi thế và bất lợi tương tự, có thể chậm hơn một chút.
4) Giải pháp Enum
Sử dụng một loại enum cho các quyền:
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
và sau đó tạo một bảng phụ cho các quyền mặc định:
CREATE TABLE item_default_permissions
(
item int NOT NULL REFERENCES items(item),
perm permission NOT NULL,
PRIMARY KEY(item, perm)
);
và thay đổi bảng định nghĩa cho mỗi người dùng thành:
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)
);
Ưu điểm : Dễ dàng đặt tên cho các quyền riêng lẻ (bạn không phải xử lý các vị trí bit).
Nhược điểm : Ngay cả khi chỉ lấy các quyền mặc định, nó vẫn yêu cầu truy cập hai bảng bổ sung: thứ nhất, bảng quyền mặc định và thứ hai, danh mục hệ thống lưu trữ các giá trị enum.
Đặc biệt vì các quyền mặc định phải được truy xuất cho mỗi lần xem trang duy nhất của mục đó , tác động hiệu suất của phương án cuối cùng có thể là đáng kể.
5) Giải pháp mảng Enum
Tương tự như 4), nhưng sử dụng một mảng để giữ tất cả các quyền (mặc định):
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
CREATE TABLE items
(
item serial PRIMARY KEY,
granted_permissions permission ARRAY,
...
);
Ưu điểm : Dễ dàng đặt tên cho các quyền riêng lẻ (bạn không phải xử lý các vị trí bit).
Nhược điểm : Phá vỡ hình thức bình thường thứ 1 và hơi xấu xí. Chiếm một số lượng đáng kể các byte liên tiếp nếu số lượng quyền lớn (khoảng 50).
Bạn có thể nghĩ về các lựa chọn thay thế khác?
Cách tiếp cận nào nên được thực hiện và tại sao?
Xin lưu ý: đây là phiên bản sửa đổi của câu hỏi được đăng trước đó trên Stackoverflow .
bigint
trường (mỗi trường tốt cho 64 bit) hoặc chuỗi bit. Tôi đã viết một vài câu trả lời liên quan về SO có thể giúp ích.