【发布时间】:2013-04-10 19:20:18
【问题描述】:
这是我的带有自动增量列的语言表定义(DBMS 是 MySQL):
DROP TABLE IF EXISTS languages;
CREATE TABLE IF NOT EXISTS languages (
language VARCHAR(16) NOT NULL,
PRIMARY KEY (language)
) ENGINE=InnoDB;
这是它的另一个版本,但应用了 UNIQUE 约束:
DROP TABLE IF EXISTS languages;
CREATE TABLE IF NOT EXISTS languages (
language_id TINYINT NOT NULL AUTO_INCREMENT,
language VARCHAR(16) NOT NULL,
PRIMARY KEY (language_id),
UNIQUE (language)
) ENGINE=InnoDB;
对于哪个版本更好用,我有两种看法。一方面,根据数据库设计理论,第一个定义似乎是正确的,只是因为其中没有多余的垃圾,而且 PRIMARY KEY 约束保证不能有两行具有相同的值,也就是说,有例如,“English”这个词不可能在列中出现两次,这当然是一件好事。但是这样做的问题是另一个表中引用语言列的外键字段必须存储字符串而不是 ID 号。这仅仅意味着引用表将把整个内容存储在列中,如果应用程序可以提供一个下拉组合框列表,其中包含预先填充的唯一值,那么拥有语言表似乎没有意义。但是从理论上讲,第一种方式还是比较正确的。
另一方面,第二种方法听起来更实用。为了确保唯一性,我们可以使用 UNIQUE 约束,并且在引用列中使用整数而不是字符串,这往往会占用更少的内存,而且据我所知,它们在搜索操作期间比字符串快得多。
请帮我弄清楚。
【问题讨论】:
-
你已经明白了。恕我直言,这是模式设计中的偏好问题。通常,您在整个架构中始终如一地使用一种或另一种方式。因此恕我直言,问题是您是否准备好在整个架构中使用自然键。
-
假设您在输入语言名称时打错字(例如“Germain”而不是“German”。现在在第一种情况下,您必须在 both语言表和 通过 FK 引用它的表。在第二种情况下,您只需进行一次更正。
-
使用第一种方法,您可以添加 ON UPDATE CASCADE 子句来处理它。
-
是的,可以。但这会在 person - 表中级联成 50M 行,其中有一个“preferred_language”字段,其中包含该表的外键。
-
我不明白你的意思。如果您使用第二种方法,它不会仍然在引用语言表的表中级联相同的 5000 万行吗?