我的数据库有两个表,一个包含用户列表,另一个包含角色列表。每个用户都属于一个或多个角色,当然每个角色中都有多个用户。
我遇到了两种链接信息的方法。第一种是添加第三个表,其中包含两个表中的ID。然后,简单连接将返回属于角色的所有用户或用户所属的所有角色。但是,随着数据库的增长,这些简单查询返回的数据集将呈指数级增长。
第二种方法是在users表中添加一个列,其中存储了分隔的角色列表。这将消除对第三个链接表的需要,这可能对数据库增长产生积极影响。缺点是SQL无法使用分隔列表。我发现处理该信息的唯一方法是使用临时表和自定义函数。
正在查看我的执行计划,“表扫描”事件是占用最多资源的事件。从等式中消除一个表会加快速度,这是有道理的。该功能占用的资源不到1%。
这些测试是在少于20条记录的数据库上完成的。随着数据库大小的增长,表扫描将花费更长时间,因此限制它们可能是最佳选择。
如果使用分隔列表是一个很好的方法,为什么没有人这样做?
请告诉我哪种方法是您首选的(即使它与我的两种方法不同)以及为什么。
谢谢。
答案 0 :(得分:10)
如果你有一个分隔列表,找到具有给定角色的用户将变得非常昂贵:实际上,你需要对该表进行全面扫描,并查看每一行中该列的所有值,尝试看它是否包含一个给定的角色。
一个单独的表(规范化,多对多关系)是可行的方法,通过适当的索引,您将无法进行完整扫描。
例如:
User: UserId, Name, ....
Role: RoleId, Name, ....
UserRole: UserRoleId, UserId, RoleId
(UserRoleId是可选的,你可以选择让PK为UserId + RoleId,我不会在这里讨论代理复合键和复合键)
您需要一个UNIQUE的(UserId,RoleId)索引来强制执行不重复的操作。这也有助于您尝试查看特定用户是否具有特定角色的任何查询(WHERE userId = x AND roleId = y)
如果您要查找用户拥有的所有角色,您只需要一个UserId索引。
相反,如果您正在查找给定角色的所有用户,那么只有roleId的索引会加快速度。如果你不进行这个查询,或者很少这样做,那么没有这个索引会为插入/更新稍微加快性能,因为它少做一件事。这是数据库调优的谨慎平衡行为。
答案 1 :(得分:8)
表扫描表示您没有任何索引,或者您的查询不允许使用它们。在安全数据库中,除非是管理员应用程序,否则您很少需要下载整个用户/角色列表。您需要在设计中解决这个问题。
定界列表违反了第一范式(1NF),几乎总是会导致长期问题。如果要检索特定角色中的所有用户,会发生什么?你怎么写那个查询?不要走这条路。将其标准化。
如果您使用的是正确的列类型(即不是varchar(4000)
或varchar(max)
无处不在),磁盘空间确实应该不是问题。是的,它会“成倍地”增长 - 那又怎样?数据库擅长这种扩展。除非您尝试在10 gig硬盘上运行此功能,否则不必担心。如果您 尝试在10 GB硬盘上运行它,您可能需要担心更大的问题。
简答:不要使用分隔列表。正常化。
答案 2 :(得分:6)
第一个选项。它被称为多对多连接表。如果您创建适当的索引,这将执行正常。
不要使用第二个'denormalised'选项。
答案 3 :(得分:4)
你可以使用一个单独的桌子,或者你可以用凿子回到穴居人。选择取决于你。
答案 4 :(得分:2)
单独的表是可行的方法,否则您将尝试解决数据库引擎问题。一个单独的表被正确规范化 - 通常,随着应用程序的扩展,规范化越好,您就越容易找到它。上面提到的greg也是绝对正确的。
答案 5 :(得分:0)
虽然我强烈推荐每个人都建议的规范化方法。我相信拥有一个基于枚举的角色系统可以让你有一个数字用于“角色”列,并允许你避免创建另一个表。