【问题标题】:"Extend" relationship in a relational database在关系数据库中“扩展”关系
【发布时间】:2011-07-17 21:37:22
【问题描述】:

您好,
我目前正在尝试应用最有效的方式在关系数据库中存储实体之间的“扩展”关系。

为了举例,假设我们有以下简化实体:

  • User
  • Student(扩展 User
  • Teacher(扩展 User

User 包含适用于StudentTeacher 的属性。 StudentTeacher 都包含它们独有的自定义属性。

首先想到的是创建一个包含所有单一数据列的单个表(即除了一对多字段):

User
-------------
User ID
First name
Last name
Student class
Teacher office no.
Teacher description
...

然而,从存储的角度来看,这并不是很有效,因为:

  • 大部分行将包含学生,少数教师
  • 教师将拥有更多独特的列,这会浪费学生行中的空间


复制实体之间的关系会更有效:

User
-------------
User ID
First name
Last name
...


Student
-------------
User ID
Student class
...


Teacher
-------------
User ID
Teacher office no.
Teacher description
...

所以我的问题是:

  1. 上述担忧是否太过分了,即我们是否应该将存储效率留给数据库引擎?
  2. 就规范化而言,将实体拆分为 3 个表仍然可以吗?
  3. 如果这不是一个好方法,您建议如何处理关系数据库中的“扩展”关系?

谢谢。

【问题讨论】:

    标签: database-design performance normalization


    【解决方案1】:

    如果用户不能既是教师又是学生,那么您将面临一个简单的超类型/子类型问题。 (我在关系数据库设计意义上使用 supertypesubtype,而不是在面向对象编程意义上使用。)您只在“学生”中存储是正确的那些描述学生的属性,并且只将那些描述教师的属性存储在“教师”中。

    -- Supertype: users
    create table users (
      user_id integer not null unique,
      user_type char(1) not null 
        check (user_type in ('T', 'S')),
      -- other user columns
      primary key (user_id, user_type)
    );
    
    -- Subtype: students
    create table students_st (
      user_id integer not null,
      user_type char(1) not null default 'S'
        check (user_type = 'S'),
      locker_num integer not null unique 
        check (locker_num > 0),
      -- other student columns
      primary key (user_id, user_type),
      foreign key (user_id, user_type) 
        references users (user_id, user_type) 
        on delete cascade
    );
    
    -- Subtype: teachers
    create table teachers_st (
      user_id integer not null,
      user_type char(1) not null default 'T'
        check (user_type = 'T'),
      office_num char(4),
      -- other teacher columns
      primary key (user_id, user_type),
      foreign key (user_id, user_type) 
        references users (user_id, user_type) 
        on delete cascade
    );
    
    create view teachers as 
    select u.user_id,
           u.user_type,
           -- other user columns
           t.office_num
           -- other teacher columns
    from users u
    inner join teachers_st t on (u.user_id = t.user_id);
    
    create view students as 
    select u.user_id,
           u.user_type,
           -- other user columns
           s.locker_num
           -- other student columns
    from users u
    inner join students_st s on (u.user_id = s.user_id);
    

    此时,您还可以执行 dbms 要求的任何操作以使这两个视图可更新 - 触发器、规则等。应用程序代码从视图中插入、更新和删除,而不是从基表中。

    【讨论】:

    • 我不知道这在 RDBMS 世界中被称为 supertype/subtype。这将使我能够进一步研究它,但建议的解决方案应该很好用 - 非常感谢!
      关于视图 - 我计划定义它们,但在它们之上添加触发器将始终如一地减轻它 - 谢谢非常感谢您的建议。
    猜你喜欢
    • 2015-01-25
    • 2014-09-13
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 2017-12-15
    • 2017-08-04
    • 1970-01-01
    相关资源
    最近更新 更多