一个查找表或许多查找表?

时间:2014-12-19 21:01:26

标签: sql database-design

我需要保存基本会员的数据,其中包含性别,教育,专业,婚姻状况,身高,居住地状态等其他属性。

我有大约15-18个查找表都有(id,name,value),所有属性都有字符串值。

我应该为每个上述属性创建成员表tbl_members并分开15-18个查找表:

tbl_members

mem_Id
mem_email
mem_password
Gender_Id
education_Id
profession_id
marital_status_Id
height_Id
residency_status_Id

或者我应该只创建一个查找表tbl_Attributestbl_Attribute_Types

tbl_Attributes

att_Id
att_Value
att_Type_Id

示例数据:

001 - Male - 001
002 - Female - 001
003 - Graduate - 002
004 - Masters - 002
005 - Engineer - 003
006 - Designer - 003

tbl_Attribute_Types

att_type_Id
att_type_name

示例数据:

001 - Gender
002 - Education
003 - Profession

要填写查找下拉菜单,我可以选择以下内容:

SELECT A.att_id, A.att_value, AT.att_type_name
FROM tbl_Attributes A
INNER JOIN tbl_Attribute_Types AT ON AT.att_type_Id = A.att_type_Id
WHERE att_Type_Id = @att_Type_Id

以及用于保存成员的属性和值的附加表tbl_mem_att_value

tbl_mem_att_value

mem_id
att_id

member_id 001的示例数据是男,硕士,工程师

001 - 001
001 - 004
001 - 005

所以我的问题是我应该选择一个查找表还是多个查找表?

由于

4 个答案:

答案 0 :(得分:6)

永远不要为一切使用一个查找表。这将使查找事物变得更加困难,并且它可能需要多次加入每个查询,这意味着它可能会导致锁定和阻塞问题。此外,在一个表中,您无法使用良好的设计来确保描述符的数据类型是正确的。例如,假设您想要查找两个字符的状态缩写。如果你使用一个简单适合所有的表,那么它必须足够宽,以便任何查找的最大可能值,并且你失去了拒绝错误条目的可能性,因为它太长了。这是后期数据完整性问题的保证 此外,您无法正确使用外键以确保数据输入仅限于正确的值。这也会导致数据完整性问题。

除了几分钟的开发时间(可能是设计数据库中最不重要的问题)之外,使用一个表没有任何好处。有很多负面因素。

答案 1 :(得分:4)

使用多个查找表的主要原因是您可以强制执行外键约束。这对于维护关系完整性非常重要。

使用单个查找表的主要原因是您将所有字符串值放在一个位置。这对于软件的国际化非常有用。

一般来说,我会选择单独的参考表,因为关系完整性通常比国际化更重要。

有次要考虑因素。许多不同的参考表将占用比单个参考表更多的空间 - 大多数页面都是空的(您真正需要多少空间来存储性别查找信息?)。但是,由于参考表的数量相对较少,这实际上是一个非常小的问题。

使用单个表的另一个考虑因素是所有引用键都具有不同的值。这很有用,因为它可以防止不可能的连接。但是,我通过为主键和外键命名连接键来防止此问题。因此,GenderId将是Gender中的主键以及外键列。

答案 2 :(得分:2)

我自己也在努力解决同样的问题。如果查找表中唯一的东西是某种代码或id和文本值,那么它肯定只是添加"属性id"并把它全部放在一张桌子里。显而易见的优点是,您只有一个表可以创建和管理。搜索可能会更慢,因为要搜索的记录更多,但可能是您在属性ID +值id上创建索引。那时,性能是否更好有一个大表或十个小表可能取决于有关数据库引擎如何工作的各种细节和访问模式。这是一个我要说的情况,除非在实践中证明是一个问题,不要担心。

两个警告:

一:如果你创建了一个表,我会为属性名创建一个代码,然后创建另一个列来列出代码。像:

lookup_attribute(attribute_id, attribute_name)
lookup_value(attribute_id, value_id, value_text)

然后第一个表有像

这样的记录
1, 'Gender'
2, 'Marital Status'
3, 'Education'
etc

第二个是

1, 1, 'Male'
1, 2, 'Female'
1, 3, 'Undecided'
2, 1, 'Single'
2, 2, 'Married'
2, 3, 'Divorced'
2, 4, 'Widowed'
3, 1, 'High School'
3, 2, 'Associates'
3, 3, 'Bachelors'
3, 4, 'Masters'
3, 5, 'Doctorate'
3, 6, 'Other'
etc.

(对于所有属性id,值id可以是唯一的,或者它可能只在属性id中是唯一的,无论什么对你有用。它都不重要。)

二:如果除了值的文本之外还需要为某些属性存储其他数据,则将其分解为单独的表。就像你有一个属性,例如"会员级别",然后用户说每个级别有不同的会费,你需要记录这个,那么你有一个额外的字段,只适用于这个属性。那时它应该成为自己的桌子。我见过系统,他们为几个属性中的每一个都有几个额外的数据,他们创建了一个名为"额外数据"或某些此类,以及"会员级别"它持有年度会费和商店名称"它拥有商店所在的城市和商品编号"它保存了该项目的单位数量等,系统很快成为管理的噩梦。

更新

要检索价值,我们假设我们只有性别和婚姻状况作为查询。任何其他原则都是一样的。

所以我们有如上所述的怪物查找表。然后我们有成员表,比如说

member (member_id, name, member_number, whatever, gender_id, marital_status_id)

要检索你,只需写下

select m.member_id, m.name, m.member_number, m.whatever,
  g.value_text as gender, ms.value_text as marital_status
from member m
join lookup_value g on g.attribute_id=1 and g.attribute_value=m.gender_id
join lookup_value ms on ms.attribute_id=2 and ms.attribute_value=m.marital_status_id
where m.member_id=@member_id

你可以选择:

member (member_id, name, member_number, whatever)
member_attributes (member_id, attribute_id, value_id)

然后你可以得到所有的属性w

select a.attribute_name, v.value_text
from member_attribute ma
join lookup_attribute a on a.attribute_id=ma.attribute_id
join lookup_value v on v.attribute_id=a.attribute_id and v.value_id=ma.value_id
where ma.member_id=@member_id

当我尝试编写查询时,会发生这样的查询,即使值id全局唯一,这不仅具有明显的优势:这不仅可以消除必须在连接中指定属性id,而且还意味着如果你有一个例如gender_id的字段,你仍然可以在其上有一个外键条款。

答案 3 :(得分:0)

将所有查找值放入单个表中通常称为“通用查找表”或Massively Unified Code-Key(MUCK),通常被认为是设计错误。

在下面的文章中可以找到关于为什么不是一个好主意的大论据。

https://www.red-gate.com/simple-talk/sql/database-administration/five-simple-database-design-errors-you-should-avoid/