关系数据库中的“扩展”关系

时间:2011-03-18 03:55:44

标签: database-design performance normalization

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

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

  • 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. 如果这不是一个好方法,你会如何建议在关系数据库中处理“扩展”关系?
  4. 谢谢。

1 个答案:

答案 0 :(得分:2)

如果用户不能同时是教师和学生,那么您正在寻找一个简单的超类型/子类型问题。 (我在关系数据库设计意义上使用 supertype subtype ,而不是面向对象的编程意义。)你只能在“学生”中存储那些描述学生的属性,以及仅在教师中存储描述教师的属性。

-- 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所需的任何操作,以使这两个视图可更新 - 触发器,规则等等。应用程序代码从视图中插入,更新和删除,而不是从基表中插入,更新和删除。

相关问题