我正在为一家商业公司构建一个应用程序,他们需要控制谁按项目和角色查看哪些报告,该报告可以属于一个项目,并且可以被许多角色(员工角色)看到。
因此,当提交报告时,它会被标记为项目和角色,例如" project1"和{"经理","卖家"},例如,正在处理project1并且是经理的员工可以看到此报告。
我现在这样做的方式很大程度上取决于数组,这就是我所拥有的:
报告表:
项目(字符串)
角色(字符串数组)
员工表:
projects(字符串数组)//员工工作/工作的所有项目
roles(字符串数组)//员工可以有多个角色
在查询员工可以看到的报告时,我会这样做:
select *
from reports
WHERE (employee.roles && report.roles) AND (report.project = ANY (employee.projects))
我使用postgresql
问题是我认为这不会有很好的表现(我不确定) 我知道加速此查询的唯一方法是在报表(角色)列上创建GIN索引,以使重叠更快
除了表现此提示here之外,让我担心:
提示:数组不是集合;搜索特定的数组元素可能是数据库错误设计的标志。考虑为每个将成为数组元素的项使用一个单独的表。这将更容易搜索,并且可能更好地扩展到大量元素。
那么有更好的设计可以做到这一点,或者这样可以正常工作吗?
答案 0 :(得分:1)
简短的回答:你正在做的事情是合情合理的,但考虑使用int数组而不是字符串,因为它们比较快,并且注意警告。
就个人而言,我将其标准化:添加user_roles表,以及role2report和user2role。在性能方面,根据我自己的经验,最佳情况是预先计算应用程序中当前用户的role_ids,然后然后查询角色的IN子句。这意味着:
select from reports join role2report ...
触发器中的相同内容:关键是计算role_ids(或perm_ids),然后然后查询。在任何情况下,您都不希望:
select from reports join role2report join crazy_user2role_role2role_rec_view
最大的优化包括使用int数组或memcached或其他方式缓存用户的角色。这避免了不断使用疯狂的user2role加上递归的role2role视图定义,以及任何其他类型的疯狂你的规格'边缘案例引导您。介意缓存失效。
根据我的经验,缓存访问列表要复杂得多:你应该缓存谁可以阅读?写?都?有些物品是公开的吗?未登录的访客可以访问它们吗?这是一大堆问题。
如果你进行缓存,也可以使用int数组。抛入例如-1代表公共/访客访问,0代表注册/用户访问。然后在查询中使用数组重叠(注册用户自动获取行0和-1)。相应地优化你的数组以保持它们的小:如果它包含-1,那应该是唯一的值;否则为零;否则列出具有授权访问权限的角色ID。
使用数组的一个警告,顺便说一句:至少直到最近版本的Postgres(现在还不确定),没有收集数组内容的统计数据。这使得对于数据集使用数组次优,其中可以访问大多数事物的某个role_id应该导致Postgres忽略GIN索引。这是一个真正的性能杀手,因为这意味着PG将基本上获取整个表以使用适当的perms获取前10行而不是使用过滤器对其进行索引扫描。