【问题标题】:Better database design?更好的数据库设计?
【发布时间】:2011-09-24 00:35:21
【问题描述】:

我们有所有者、编辑、查看者等角色... 每个角色都有不同的权限,如下载、分享、编辑、查看等......

我为此功能创建了两个数据库设计。我必须实现哪种数据库设计?

1) Table   -> Roles 
   Columns -> Id
              Name
              isDownload
              isShare
              isView

2) Table   -> Roles
   Column  -> Id
              Name
              Description

   Table   -> Privileges
   Column  -> Id 
              Name
              Description

   Table   -> RolesPrivileges
   Column  -> Id
              RoleId
              PrivilegeId

这些设计的优缺点是什么?我必须实施哪一个? 哪个更具可扩展性和可维护性?为什么 ?

【问题讨论】:

    标签: mysql ruby-on-rails database database-design scalability


    【解决方案1】:

    第二个是要走的路。 如果需要新建角色,不需要修改表结构,只需要新建角色,关联权限等即可。 第一个设计的最大问题是角色/权限的任何更改都需要更改表结构。

    【讨论】:

    • @Franky 如何说服我的 CTO ?他提出这样的问题,如果我将在角色表中创建一行或在角色表中创建一列,有什么区别?
    • 列更改通常意味着代码、sql 语句等的更改。新角色/权限可以通过插入语句来实现。在这种情况下,只需要实现这些角色如何使用的实际实现。一切都取决于系统和这些角色的使用。
    • @KrunalShah - 我很惊讶“CTO”会问这个问题。进行此类更改涉及更多。
    • 我想 CTO 可能正在测试 krunal 的知识/研究。
    • @Franky:或者,CTO 精通 SQL,知道您不会每天都添加新权限,而且从长远来看,额外的连接可能会产生成本。
    【解决方案2】:

    这样的事情在很大程度上取决于您的数据库将如何使用 - 诸如以下因素:

    1. 灵活性 - 您将来是否可能需要添加额外的角色/权限?如果是这样,请在 #2 中选择更广泛、更灵活的表结构。
    2. 复杂性 - 如果您的数据库比普通的小型系统大,我建议您选择#2。但是,如果它非常小且非正式使用,可能值得您节省时间来使用更简单的系统。
    3. 性能 - #2 显然更复杂一些,可能需要更多查询,尤其是在您可能需要一次执行多个查询的情况下。但是,通过正确使用数据库索引可以很好地缓解这种情况。

    【讨论】:

    • +1 表示没有直接忽略选项 #1 并提及与 #2 相关的潜在性能问题。
    【解决方案3】:

    当然,第一个是要走的路:

    Table   -> Roles 
    Columns -> Id
               Name
               isDownload
               isShare
               isView
    
    • 是一个简单的设计
    • 无需 JOIN 即可从同一个表中读取角色和权限
    • 空间要求比第二种选择要少

    但是,如果您有动态权限并且经常添加或删除权限,您可能会考虑方法 2。但否则保持单个表就可以了。

    【讨论】:

      【解决方案4】:
      1) Table   -> Roles 
         Columns -> Id
                    Name
                    Description
                    isDownload
                    isShare
                    isView
      
      
      2) Table   -> UserRolesPrivileges
         Column  -> Id
                    RoleId
                    UserId
      

      UserId 来自用户注册表。

      每个用户都与各自的角色相关联 在角色表中,我想你会有不同的角色,每个角色都是 定义了它可以执行的操作。

      我没有看到任何使用权限表,只要用户与角色相关联

      【讨论】:

      • 我认为将角色与权限分开非常重要。否则,如果您需要添加更多权限,您需要的角色数量会呈指数级增长,假设您将为每种权限组合拥有一个角色。
      【解决方案5】:

      我想就选项 1 提出一个建议,以避开它的一些批评。不要为每个可能的权限使用布尔值,而是使用位掩码。

      先举个例子

      (responsible_mask INT)

      def Roles
      
          RESPONSIBILITES = [ :switchboard, :content_manager, :network_administrator, :financial_manager, :receives_contact_emails ]
      
          def responsibilites=(responsibilites)
              self.responsible_mask = ([*responsibilites].map(&:to_sym) & RESPONSIBILITES).map { |r| 2**RESPONSIBILITES.index(r) }.sum
          end
      
          def responsibilites
              RESPONSIBILITES.reject { |r| ((responsible_mask || 0) & 2**RESPONSIBILITES.index(r)).zero? }
          end
      
          def responsibilites_symbols
              responsibilites.map(&:to_sym)
          end
      
          def responsible?(responsibility="none")
              responsibilities_symbols.includes?(responsibility.to_sym)
          end
      end
      

      随时添加更多职责很容易。

      现在为什么?

      在我看来,这是更好的做法。我看不出为什么我会创建一个表单来添加另一个职责(或在您的情况下为特权)而不在我的代码中放置挂钩以使用该职责的原因。我只需要这些信息来确定我是否应该允许功能;它没有其他目的。当然,我仍然希望管理员能够创建角色并将职责分配给该角色,但它始终是固定设置。

      它还使 SQL 查询更加复杂——添加另一个连接。慢点。更难调试。

      在部署到另一台服务器时,要记住构建这个静态数据表是一件很痛苦的事情。

      【讨论】: