假设我有一个项目表:
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)整数解决方案
使用整数并将其视为位字段(即,位0用于can_change_description
,位1用于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)
);
优点:易于命名个人权限(您无需处理位)。
缺点:即使仅检索默认权限,它也需要访问两个附加表:第一,默认权限表,第二,存储枚举值的系统目录。
尤其是因为必须为该项目的每个页面视图都检索默认权限,所以最后一种选择对性能的影响可能很大。
5)枚举数组解决方案
与4)相同,但是使用数组来保留所有(默认)权限:
CREATE TYPE permission AS ENUM ('can_change_description', 'can_change_price', .....);
CREATE TABLE items
(
item serial PRIMARY KEY,
granted_permissions permission ARRAY,
...
);
优点:易于命名个人权限(您无需处理位)。
缺点:破坏了第一种正常形式,并且有点难看。如果许可数量很大(大约50个),则连续占用大量字节。
您能想到其他选择吗?
应该采用哪种方法,为什么?
请注意:这是先前在Stackoverflow上发布的问题的修改版本。
bigint
字段(每个字段适合64位)或一个位字符串。我在SO上