代码之家  ›  专栏  ›  技术社区  ›  Dereleased

是否有表示不同表中几个对象的规范化窗体?

  •  5
  • Dereleased  · 技术社区  · 15 年前

    对于我当前正在构建的系统,会出现以下两种情况:

    1. 我的权限系统是将权限附加到角色和角色到用户的常用系统,但有一个转折点:权限可以应用到任何层的任何资产,并且有4个“层”,编号为0到3。因此,角色分配表的长度为5个字段:资产层、资产ID、角色ID、用户ID和“禁用”标志。此“层/ID”系统还用于将用户分配给“家庭资产”。

      这个系统不幸的副作用是,通常在应用程序本身中而不是在SQL中解析这些资产引用要简单得多(我知道这是可能的,但它会导致一些非常难看的查询)。 有没有更好的方法来表现这种关系?这是表示这种关系的一种可接受的方式吗?

      旁注:资产本身的表(它们是层次结构)是规范化的,外键引用指向子级到父级(例如,第3层包含有关第2层的信息等),因此一旦固定了单个资产,就很容易找到其子级和父级。

    2. 类似的问题,但不同的数据上下文:在最低层,设备可以“附加”。设备也可以放置在图形表示上(如地图),它们的排列信息存储在数据库中。图形引用(也称为“点”)应指向实际设备,但实际设备可能不指向图形引用。

      目前,所有“点”(代表设备)都有一个单一的参考表,其中包含显示布局、位置、大小等信息。我可以从这里确定三种可能的操作:

      1. 创建一系列规范化的表来表示单个设备,并使用类似的“设备类型/设备ID”系统来查找它们,并将此信息存储在“点”表中;这仍然需要应用程序在解决这些对其各自表中的实际设备的引用时进行中间工作。
      2. 创建一系列规范化的表,并将它们指向“点”表;此解决方案可能不需要应用程序取消引用点数据,但需要扫描所有设备表以查找任何第3层对象。
      3. 使用点表作为准则,将所有相关显示数据添加到每个相应的规范化表中。虽然这将阻止必须解决任何查找,但仍然需要扫描每个设备表,而且与其他解决方案相比,对点数据存储方式的任何更改也极其不容忍。

      这个问题已经解决了吗?我只是没有收到备忘录?是否有一个标准的设计来解决这个问题,或者我应该假设我必须自己解决这些引用?

    注:关于第二个问题,我认为以下两个解决方案是可怕的,我不会考虑它们(除非有一些疯狂的、令人惊奇的证据表明这是最好的方法,我相当肯定这不是最好的方法):

    1. 将有关每个设备的所有信息(在序列化数组或某些此类机制中)存储在Points表本身中。 这有一个明显的问题,即完全不可测和违背正常形式。
    2. 将所有设备存储在一个通用表中。 不幸的是,这些设备在它们提供的数据类型以及必须如何访问这些设备上都有极大的不同,在一个表中这样做需要至少30列(可能更多),其中超过一半的列对于每一行都是空的。

    尽管我特别寻找现有的模式和/或规范化的模式来解决这个问题(如果存在的话),但是任何解决方案都是被请求和赞赏的。如果您知道这是正确的答案,“否”就足够了,我将继续使用应用程序层来解析这些引用。这还不是问题,我只是想知道,当有人已经解决了这个/这些问题时,我并没有朝着错误的方向走。事先谢谢。

    编辑:权限/资产架构

    第0层实际上是隐含的,不在数据库中,但某些内容注册为第0层(资产ID 0)

    第1层:

    id int(5) unsigned not null primary key auto_increment,
    name varchar(32) not null,
    disabled tinyint(1) unsigned not null,
    

    第2层:

    id int(5) unsigned not null primary key auto_increment,
    parentId int(5) unsigned not null,
    name varchar(32) not null,
    abbr varchar(16) not null,
    disabled tinyint(1) unsigned not null,
    foreign key (parentId) references tier1(id)
    

    第3层:

    id int(5) unsigned not null primary key auto_increment,
    parentId int(5) unsigned not null,
    name varchar(32) not null,
    abbr varchar(16) not null,
    disabled tinyint(1) unsigned not null,
    foreign key (parentId) references tier2(id)
    

    权限:

    id int(5) unsigned not null primary key auto_increment,
    permission_key varchar(16) not null,
    permission_desc varchar(128) not null
    

    角色:

    id int(5) unsigned not null primary key auto_increment,
    name varchar(32) not null,
    tier1_id int(5) unsigned not null,
    disabled tinyint(1) unsigned not null,
    foreign key (tier1_id) references tier1(id)
    

    角色权限:

    role_id int(5) unsigned not null,
    permission_id int(5) unsigned not null,
    disabled tinyint(1) unsigned not null,
    primary key (role_id, permission_id),
    foreign key (role_id) references roles(id),
    foreign key (permission_id) references permissions(id)
    

    用户角色权限:

    tier_id tinyint(1) unsigned not null,
    asset_id int(5) unsigned not null,
    user_id int(5) unsigned not null,
    role_id int(5) unsigned not null,
    disabled tinyint(1) unsigned not null,
    primary key (tier_id, asset_id, user_id, role_id),
    foreign key (user_id) references users(id),
    foreign key (role_id) references roles(id)
    
    1 回复  |  直到 15 年前
        1
  •  4
  •   Sarah Happy    15 年前

    您是否考虑将权限表拆分为一组表,每个表都应用于一个单独的对象表,例如,第一层资产和第一层权限,以及第二层资产和第二层权限。这将使查询一层资产的权限更简单,但查询用户的所有权限更复杂(这是一种权衡)。

    我还将挑战这样一个假设:关系数据库是您数据的正确存储介质。它可能确实是,但也可能不是。(在这方面,PHP可能会限制自由)。

    如果您的数据集很小,为什么不将其保存到单个序列化文件中,并有一个小型服务器将其保存在内存中并提供查询接口?我相信有充分的理由不这么做。(除了在PHP中)

    你考虑过第二个问题的多点表吗?它可能感觉像是一个重复,但它确实使某些类型的查找变得更简单,并且当您将每个外键引用视为不同类型的对象时(当表被分离时,您可以对它们使用外键检查),它会被规范化。

    对象之间关系的多样性应该告诉您将键和引用放在哪里:一对多->(键<-外键);多对多->(键<-链接表->键);一对可选->(键<-外键)。

    我不知道有什么模式能符合你所说的问题。但我注意到,大多数避免创建另一个表的通用解决方案都很难快速管理。