我们有一个使用SQL Server 2012作为数据库的客户端 - 服务器系统。系统会定期更新和增强。
我们最近意识到我们有一个重复的表设计模式:一个表,它将Users表链接到数据库中的其他表,形成了视图和权限的基础。示例:
CREATE TABLE Documents_Users (
ID int not null identity(1,1) not for replication,
UserID int not null, -- foreign key to the Users table
DocumentID int not null, --- foreign key to the Documents table
[...]
)
我们在想,不是创建所有这些表,而是创建一个这样的大表:
CREATE TABLE UserPermissions (
ID int not null identity(1,1) not for replication,
UserID int not null, -- foreign key to the Users table
ObjectID int not null, -- pointer to any object ID in another table
TableID int not null, -- actual id of the referenced table in sys.objects
[...]
)
优点:一个表解决了所有当前和未来表的所有权限需求。
缺点:
没有外键。我们将不得不创建一个偶尔运行的作业并删除孤立指针(如果我们不在存储过程中删除它们)。
视图需要按照
的方式进行查询从[some_table]中选择*,其中ID为( 从UserPermissions中选择ObjectID,其中TableID = object_id(' someTableName') )
创造像这样的概括是否值得,并且是一种好的做法?有一个表和一个索引可以读取,而不是可能有很多不同的表吗?
答案 0 :(得分:2)
我的直觉是,这可能不是一个好主意。
更好的选择是使用继承 1 :
您添加的任何未来表,您只需从现有基表继承,它们将自动插入"你已经实施的安全逻辑。
对于它的价值,我们目前正在这样的架构之上实现一个相当强大的安全机制,到目前为止它运作良好。
1 在ER建模中也称为:"类别"或者"泛化层次"或"继承"等
2 不幸的是,今天的关系数据库并没有直接支持继承(甚至PostgreSQL都没有,只能部分实现它),所以你需要模拟它(这里是one example并且您可能还想阅读this),这会带来自身的问题,但在某些情况下仍然非常有用。
答案 1 :(得分:0)
我现在面临同样的选择,我想我会选择通用解决方案。我不是泛型解决方案的粉丝,因为语义不太明显,在你知道它之前,你处在一个难以理解的混乱中。但我倾向于认为它是允许的,如果它服务于域范围,明确定义的目的,例如日志,语言等,安全性。
对于反对意见,我认为删除的孤儿不会妨碍任何事情,所以偶尔清理一次就是一个很好的解决方案。 至于查询,我将创建一个内联表值函数,也就是将UserId作为参数的参数化视图(而不是每个表的视图)。可以选择性地限制表本身的读取权限,并且只允许对视图的权限。
我认为性能提升是微不足道的,但通用解决方案仍然会更好;我的主要原因是图表不那么杂乱。
答案 2 :(得分:0)
我不会这样做,因为当用户到X权限需要基于X的类型的属性时会发生什么。即UserDocumentPermission可能具有读取,写入,删除,添加等,而UserCarPermission可能具有驱动,启动和停放权限。
谁在乎你是否有很多牌桌。您只需使用命名约定即可轻松记住。