【问题标题】:An auto-increment column or the UNIQUE constraint?自增列还是 UNIQUE 约束?
【发布时间】: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 万行吗?

标签: mysql sql


【解决方案1】:

我在这里Should an SQL Dictionary table have an IDENTITY column问过类似的问题

在这种情况下,我发现没有 ID 列是正确的决定,因为我永远不会通过代码中的 PK 以外的任何方式引用数据。那就是没有依赖于该表的外键。

如果您正在查找一些任意数据或将其作为外键引用,我总是主张使用 id 列,因为它会减小数据库的大小并且可以立即识别它对于任何拥有最基本数据库知识的人来说,它都是一个外键。

【讨论】:

    【解决方案2】:

    第二个版本更加规范化。在数据库设计理论中有 1NF(第一范式)、2NF 到 6NF 的概念。 1NF 意味着您只有某种密钥。 6NF 意味着您的数据结构尽可能干净。高标准化听起来不错,但您要付出代价:

    • 更复杂的查询和插入操作
    • 由于所有这些复杂性而导致性能下降

    如有疑问,我总是会选择不太复杂的选项。如果有一天你真的需要全面优化或规范化,你可以在那天改变你的架构。不确定您的数据库有多大,但如果您仔细进行重构,可能会轻而易举。

    【讨论】:

    • 可能调用重构小菜一碟?我不知道你对那部分的回答是否相当准确。
    • 嗯,在我看来,它们在标准化方面是相同的。你不这么认为吗?你说第二个版本更加规范化。我想看看在什么方面是这样。
    • @Sparksis:添加一列并不神奇。也没有用递增的数字填充该列。即使你不熟悉 MySQL,谷歌搜索也需要 20 分钟。考虑到 OP 听起来他不使用 ORM,代码的更新也是不费吹灰之力的。事实上,更新代码将是他现在可以做的额外努力。
    • @MikhailRybkin:正如上面 cmets 所指出的,密钥(ab)用作数据容器。尽管 OP 没有澄清这一点,但在我看来,他将在 UI 中显示密钥似乎很明显。这会影响规​​范化的示例:您意识到应该编写 Français 而不是 Francais。将它放在额外的列中意味着您不必更新其他表中的列。 ...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-17
    • 2011-04-29
    • 2015-09-24
    • 2021-12-09
    • 2017-08-05
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多