Mysql 自动递增列还是唯一约束?

Mysql 自动递增列还是唯一约束?,mysql,sql,Mysql,Sql,这是我的语言表定义,带有一个自动递增列(DBMS是MySQL): 这是它的另一个版本,但应用了唯一的约束: 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

这是我的语言表定义,带有一个自动递增列(DBMS是MySQL):

这是它的另一个版本,但应用了唯一的约束:

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;
对于哪个版本更适合使用,我有点犹豫不决。一方面,根据数据库设计理论,第一个定义似乎是正确的,因为其中没有多余的垃圾,并且主键约束保证不能有两行具有相同的值,也就是说,例如,“English”一词不能在列中出现两次,当然,这是件好事。但问题是,另一个引用语言列的表中的外键字段必须存储字符串,而不是ID号。这仅仅意味着引用表将在列中存储整个内容,如果应用程序可以提供一个下拉组合框列表,其中包含预先填充的唯一值,那么使用languages表似乎没有意义。但是,从理论上讲,第一种方法更为正确

另一方面,第二种方法听起来更实用。为了确保唯一性,我们可以使用UNIQUE约束,在引用列中使用整数而不是字符串,这往往占用更少的内存,而且据我所知,在搜索操作中,它们比字符串快得多


请帮我弄清楚这一点。

我在这里问了一个类似的问题

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


在查找任意数据段或将其作为外键引用的情况下,我始终主张使用id列,因为它将减少数据库的大小,并且对于任何具有最基本数据库知识的人都可以立即识别它是外键

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

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

如果有疑问,我总是选择不太复杂的选项。如果有一天您真的需要完全优化或规范化,您可以在那天更改您的模式。不确定您的数据库有多大,但如果您仔细进行重构,重构可能是小菜一碟。

您已经明白了这一点。在模式设计中,这是一个偏好的问题。通常,您在整个模式中始终使用一种或另一种方式。因此,问题是你是否准备好在整个模式中使用自然键。想象一下,你在输入语言名称时输入了一个拼写错误(例如“Germain”而不是“German”.现在,在第一种情况下,您必须在languages表和通过FKs引用该表的表中修复该问题。在Secando情况下,您只需进行一次更正。使用第一种方法,您可以添加ON UPDATE CASCADE子句来处理该问题。是的,可以。但这将在person-table中级联成50万行,其中是一种“首选语言”字段与此表的外键。我不明白你的意思。如果你使用第二种方法,它是否仍然会在引用语言表的表中层叠通过相同的5000万行?可能称重构为小菜一碟?我不知道你在这一部分的回答相当准确。嗯,在我看来,它们在不同方面是相同的规范化的erms。你不这么认为吗?你说第二个版本更规范化了。我想看看它在什么方面是这样的。@Sparksis:添加一个列不是魔术。用递增的数字填充该列也不是魔术。即使你不熟练使用MySQL,谷歌搜索也需要20分钟。代码的更新也不是魔术给定OP听起来好像他没有使用ORM。事实上,更新代码将是他现在可以做的额外工作。@MikhailRybkin:正如上面评论中指出的,关键是(ab)用作数据容器。尽管OP没有对此进行澄清,但我认为他显然会在UI中显示密钥。这会影响规范化的示例:您意识到应该编写Français而不是Francais。将其放在一个额外的列中意味着您不必更新其他表中的列。。。
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;