MySQL术语“约束”与“外键”的区别?

时间:2008-11-21 23:42:27

标签: mysql foreign-keys constraints ddl

我正在查看MySQL文档here并尝试理清FOREIGN KEY和CONSTRAINT之间的区别。我认为FK 约束,但是文档似乎在谈论它们,就像它们是分开的东西一样。

创建FK的语法是(部分)......

[CONSTRAINT [symbol]] FOREIGN KEY
    [index_name] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name,...)

所以“CONSTRAINT”子句是可选的。你为什么要包括它或不包括它?如果你把它留下来,MySQL会创建一个外键但不是约束吗?或者它更像是一个“CONSTRAINT”只不过是你FK的名字,所以如果你没有指定它,你会得到一个匿名的FK?

非常感谢任何澄清。

谢谢,

7 个答案:

答案 0 :(得分:58)

是的,外键是一种约束。 MySQL对约束的支持不均衡:

  • PRIMARY KEY:是表约束和列约束。
  • FOREIGN KEY:是表约束,但仅限于InnoDB和BDB存储引擎;否则解析但忽略。
  • CHECK:解析但在所有存储引擎中都被忽略。
  • UNIQUE:是表约束和列约束。
  • NOT NULL:是列约束。
  • DEFERRABLE和其他约束属性:不支持。

CONSTRAINT子句允许您显式命名约束,以使元数据更具可读性,或者在您想要删除约束时使用该名称。 SQL标准要求CONSTRAINT子句是可选的。如果将其遗漏,RDBMS会自动创建一个名称,名称取决于实现。

答案 1 :(得分:9)

通常(不是必需的MySQL),外键是约束,但约束并不总是外键。考虑主键约束,唯一约束等。

回到具体问题,你是对的,省略CONSTRAINT [symbol]部分将创建一个带有自动生成名称的FK。

答案 2 :(得分:3)

截至目前,我们的CREATE TABLE DDL具有这种格式 - 请注意我们使用的UNIQUE KEY和FOREIGN KEY定义语法。

CREATE TABLE my_dbschema.my_table (
    id INT unsigned auto_increment PRIMARY KEY,
    account_nbr INT NOT NULL,
    account_name VARCHAR(50) NOT NULL,
    active_flg CHAR(1) NOT NULL DEFAULT 'Y',
    vendor_nbr INT NOT NULL,
    create_ts TIMESTAMP NOT NULL DEFAULT current_timestamp,
    create_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
    last_upd_ts TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
    last_upd_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
    UNIQUE KEY uk1_my_table(account_nbr, account_name),
    FOREIGN KEY fk1_my_table(vendor_nbr) REFERENCES vendor(vendor_nbr)
    );

在这种格式中,MySQL自动创建名为uk1_my_table和fk1_my_table的INDEX-es;但是FK对象名称是不同的 - my_table_ibfk_1(即tablename_ibfk_N - 系统定义)。所以ALTER TABLE my_table DROP FOREIGN KEY fk1_my_table将不起作用(因此令人沮丧并引发警报),因为该名称没有FK db对象。

这是一个替代DDL格式的常数(参考:https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html): -

CREATE TABLE my_dbschema.my_table (
    id INT unsigned auto_increment PRIMARY KEY,
    account_nbr INT NOT NULL,
    account_name VARCHAR(50) NOT NULL,
    active_flg CHAR(1) NOT NULL DEFAULT 'Y',
    vendor_nbr INT NOT NULL,
    create_ts TIMESTAMP NOT NULL DEFAULT current_timestamp,
    create_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
    last_upd_ts TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
    last_upd_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
    CONSTRAINT uk1_my_table UNIQUE KEY (account_nbr, account_name),
    CONSTRAINT fk1_my_table FOREIGN KEY (vendor_nbr) REFERENCES vendor(vendor_nbr)
    );

在这种格式中,MySQL仍然会自动创建名称为uk1_my_table和fk1_my_table的INDEX-es,但FK对象名称并不相同 - 它是DDL中提到的fk1_my_table。所以ALTER TABLE my_table DROP FOREIGN KEY fk1_my_table有效,但留下了同名的INDEX。

并且,请注意ALTER TABLE my_table DROP INDEX fk1_my_table最初不起作用(当FK尚未删除时),并显示错误信息,表明它正在FK中使用!如果已成功执行DROP FK命令,则只有DROP INDEX才能运行。

希望这能解释并帮助解决困惑。

答案 3 :(得分:1)

无法回答MySQL,但FK是限制因素。任何迫使您的数据进入特定条件的东西都是一种约束。有几种约束,唯一,主键,检查和外键都是约束。也许MySQL还有其他人。

有时在命令中允许使用单词,但为了便于阅读,不需要像DELETE语句中的FROM那样。

答案 4 :(得分:1)

如果我没有错,那么约束需要索引,所以当你创建一个外键约束时,MySQL也会自动创建一个索引。

答案 5 :(得分:0)

这可能是MySQL中最令人困惑的topìc。

许多人说,例如,'PRIMARY KEY','FOREIGN KEY'和'UNIQUE'键实际上是索引! (MySQL官方文档包含在这里)

另一方面,许多其他人说他们是相当的约束(这确实有意义,因为当你使用它们时,你真的对受影响的列施加了限制)。

如果它们确实是索引,那么使用约束clausule为它命名是什么意思,因为你应该在创建它时能够使用该索引的名称?

示例:

... FOREIGN KEY index_name(col_name1,col_name2,...)

如果FOREIGN KEY是索引,那么我们应该能够使用index_name来处理它。但是,我们不能。

但如果它们不是索引而是使用索引工作的实际约束,那么这确实有意义。

无论如何,我们不知道。实际上,似乎没有人知道。

答案 6 :(得分:0)

我要在这里吐槽一下,虽然我实际上并不知道我的回答是否准确,所以如果您了解数据库工程的内部结构,请指正。但如果我是对的,我认为这会有所帮助。

外键及其关联的外键约束不是一回事,就像汽车发动机和曲轴不是一回事一样。发动机将汽油爆炸转化为直线运动(活塞),曲轴将这种直线运动转化为转动运动,然后转动汽车的车轮。发动机和曲轴共同推动汽车行驶。

同样,外键和外键约束不是一回事,但它们共同创造了“外键关系”的概念。

定义:

“外键”是外键索引的缩写。

“约束”是外键约束的缩写。

索引和约束共同构成了“外键关系”。

外键关系是要求子表中的值存在于其父表中,从而确保数据库中的数据完整性。

因为 Key 表示索引,所以我们不说“外键索引”。我们只说外键,而不说“索引”是造成很多混乱的原因。

Creating a Foreign Key(外键索引)会创建一个二叉搜索树(也称为字典,因为树是用来查找值的)。二叉搜索树 (BST) 然后存在于计算机内存中并占用物理磁盘空间,但允许从子表到父表的 O(log n) JOIN 访问时间(几乎立即)。

创建外键约束就是创建一个规则,这是一段代码,当您在外键列上处理(INSERT、SELECT 等...)时会调用该代码。约束本质上是一个数据库触发器。约束就像一个电子邮件过滤器:一段代码在某个动作上被调用,例如 WHEN(新电子邮件)IF(来自:crzy@xgfrnd.com){SEND TO Trash Folder;}。

因此,外键“约束”将是一段被调用的代码(本质上是一个触发器),看起来像这样:WHEN INSERT child_column IF (NOT IN parent_table) DO NOT ALLOW INSERT。

然后你有你的级联和更新和删除规则(约束),以及它们的各种 if / then 条件和操作等......

因此,“外键”是将子表列值映射到父表列值的 BST 字典。外键的目的是速度(不是数据完整性,因为可以实现数据完整性,尽管速度很慢,没有索引)。

外键约束是一条规则:在 SQL 语句上触发的代码,该规则使用 BST 作为字典进行快速处理,以避免遍历表,这最终可能会产生类似笛卡尔的行为。外键约束的目的是数据完整性。

我从未创建过父表,其中引用的父列本身不是父表中的键。那么问题来了,外键索引(BST 字典)真的需要吗? Constraint 肯定是需要的,以保证数据的完整性,但实际上并不需要外键索引(BST 字典)来满足外键规则,因此“键”和“索引”有两个不同的定义。 “Index”是BST树,“Key”是规则(子值必须存在于父表中的想法)。然而,在 MySQL 中,需要外键索引,只是因为他们以这种方式编程,但他们没有必要这样做。当父列本身没有被索引时,拥有 BST 树会更快。我永远不会建议将引用的父列设为键(索引)。但是,如果有人确实使用没有 BST 的外键约束引用了非索引父列,那么 SQL 操作将逐渐变慢,您的应用程序最终可能会爬行。

混淆:形容词和动词。

当我们通俗地说“外键”时,我们通常指的是外键关系,而不是外键索引。但是关键字这个词的意思是索引。所以这就是所有混乱的根源。 IE。缺乏保留关键字定义标准。在 MySQL CREATE TABLE 语句中,FOREIGN KEY 表示索引(BST),而 CONSTRAINT 命名规则,因此,混淆来自我们说话时短语“Foreign Key”与定义的“Foreign Key”的区别在实际的 SQL 语句中。

在计算机代码中,“Foreign”是形容词,“Key”是名词,意思是索引。

在口语中,“外键”是形容词,“索引”、“约束”、“关系”都是名词。当我们在办公室隔间互相交谈时,“外键”意味着数据完整性的“想法”(即规则,而不是索引)。

不幸的是,程序员总是在寻找速记的打字方式,这往往会引起混淆。计算机科学中的一切都是一种权衡,包括编码风格。

如果创建 MySQL 表的语法改为使用以下保留字,那么混淆就会消失: FOREIGN KEY CONSTRAINT fk1_rule_child_column FOREIGN KEY INDEX (fk_bst_child_to_parent_column) REFERENCES parent_table ({ {1}})

此外,由于 MySQL 总是同时创建索引和约束,因此 MySQL 创建者可以完全隐藏(抽象)外键关系的双重元素。或者,也许我应该说,他们可以将它们捆绑在一起,这样用户就不必考虑双重方面,而只需创建一个隐藏双重细节的“外键”parent_column

尽管如此,MySQL 便宜、健壮,而且很棒。郑重声明,我的投诉为零,我只对创作者表示感谢。就我而言,他们可以随心所欲。

顺便说一下,作为样式建议,您应该始终将父列和子列命名为相同的名称,并且您的表名应始终包含它们的外键关系。所以你的桌子

my_foreign_key customers products attributes

应该改为命名

orders customers products product_attributes

这样,您和您的继任者只需读取任何表名即可知道外键关系。如果这对您来说打字太多,那么

customer_product_orders cust prod prod_attr

话虽如此,我猜。我实际上不知道我的 BST 和规则解释是否正确,但我认为它是正确的,希望能解决这个令人困惑的问题。但是,如果你们这些数据库胆量的家伙确认、修改、补充或否认我写的东西,如果我弄错了,真正的答案是什么,我们最终可以解决这个多代人的谜团,我将不胜感激.如果我完全关闭,并且需要删除此答案,那也可以。