为什么在理论上比实践上更多地使用外键?

当您学习关系理论时,外键当然是必需的。 但是实际上,在我工作过的每个地方,表产品和联接总是通过在查询中显式指定键来完成的,而不是依赖于DBMS中的外键。

这样,您当然可以通过不属于外键的字段联接两个表,从而产生意外结果。

你为什么这么认为呢? DBMS不应该强制联接和产品仅由外键进行吗?

编辑:感谢所有的答案。 现在我很清楚,FK的主要原因是参考完整性。 但是,如果您设计数据库,则至少从理论上讲,模型中的所有关系(ERD中的I.E.箭头)都将成为外键,无论您是否在DBMS中将它们定义为外键,它们在语义上都是FK。 我无法想象需要通过不是FK的字段来联接表。 有人可以举一个有意义的例子吗?

PS:我知道N:M关系成为单独的表而不是外键的事实,为简单起见,省略了它。

Petruza asked 2020-02-16T22:39:46Z
17个解决方案
39 votes

存在外键约束的原因是为了确保引用的行存在。

“外键标识一个表中的一列或一组列,它引用另一张表中的一列或一组列。引用列的一行中的值必须出现在被引用表的一行中。

因此,引用表中的行不能包含引用表中不存在的值(可能为NULL除外)。 可以通过这种方式将信息链接在一起,并且这是数据库规范化的重要组成部分。”(维基百科)


RE:您的问题:“我无法想象需要通过不是FK的字段来联接表”:

定义外键约束时,引用表中的列必须是被引用表的主键,或者至少是候选键。

进行联接时,无需使用主键或候选键进行联接。

以下是一个可能有意义的示例:

CREATE TABLE clients (
    client_id       uniqueidentifier  NOT NULL,
    client_name     nvarchar(250)     NOT NULL,
    client_country  char(2)           NOT NULL
);

CREATE TABLE suppliers (
    supplier_id       uniqueidentifier  NOT NULL,
    supplier_name     nvarchar(250)     NOT NULL,
    supplier_country  char(2)           NOT NULL
);

然后查询如下:

SELECT 
    client_name, supplier_name, client_country 
FROM 
    clients 
INNER JOIN
    suppliers ON (clients.client_country = suppliers.supplier_country)
ORDER BY
    client_country;

这些联接有意义的另一种情况是在具有地理空间功能的数据库中,例如SQL Server 2008或带有PostGIS的Postgres。 您将可以执行以下查询:

SELECT
    state, electorate 
FROM 
    electorates 
INNER JOIN 
    postcodes on (postcodes.Location.STIntersects(electorates.Location) = 1);

来源:ConceptDev-SQL Server 2008地理区域:STIntersects,STArea

您可以在帖子“ SQL 2008查询问题-地理多边形中存在哪个LatLong”的答案中看到另一个类似的地理空间示例:

SELECT 
    G.Name, COUNT(CL.Id)
FROM
    GeoShapes G
INNER JOIN 
    CrimeLocations CL ON G.ShapeFile.STIntersects(CL.LatLong) = 1
GROUP BY 
    G.Name;

这些都是有效的SQL连接,与外键和候选键无关,并且在实践中仍然有用。

Daniel Vassallo answered 2020-02-16T22:40:44Z
34 votes

外键与连接无关,而与保持数据库完整性有关。 证明是,您可以以任何所需的方式连接表,即使这些连接不一定有意义。

Otávio Décio answered 2020-02-16T22:41:04Z
10 votes

我无法想象需要通过不是FK的字段来联接表。 有人可以举一个有意义的例子吗?

仅当SQL模型的实体之间的关系反映为关系模型中两个关系之间的等价关系时,才能使用PriceRanges强制执行参照完整性。

这并非总是如此。

这是我前段时间写在博客中的文章的示例:

  • 什么是实体关系模型?

该模型描述了商品和价格范围:

这是模型的关系实现:

CREATE TABLE Goods (ID, Name, Price)
CREATE TABLE PriceRange (Price, Bonus)

如您所见,PriceRange表仅具有一个与价格相关的属性SQL,但是该模型具有两个属性:StartPriceEndPrice

这是因为关系模型允许转换集合,并且可以使用SQL操作轻松地重建实体PriceRange

Goods
ID  Name               Price
1   Wormy apple        0.09
2   Bangkok durian     9.99
3   Densuke watermelon 999.99
4   White truffle      99999.99

PriceRange
Price   Bonus
0.01       1%
1.00       3%
100.00    10%
10000.00  30%

我们仅存储每个范围的下限。 上限很容易推断出来。

这是查找每种商品的奖励的查询:

SELECT  *
FROM    Goods
JOIN    PriceRange
ON      PriceRange.Price =
        (
        SELECT  MAX(Price)
        FROM    PriceRange
        WHERE   PriceRange.Price <= Goods.Price
        )

我们看到这些关系模型很好地实现了ER模型,但是在这些关系之间不能声明任何外键,因为用于绑定它们的操作不是等联接。

Quassnoi answered 2020-02-16T22:42:14Z
8 votes

不,不需要执法; 它会禁止某些有用的功能,例如可能的列重载。 尽管这种用法并不理想,但在某些实际情况中很有用。

外键约束的适当用法就是这样; 对添加到给定列的值的约束,以确保它们引用的行存在。

应该注意的是,在给定模式上明显缺乏外键约束是不好的“气味”,并且可能表明一些严重的设计问题。

Paul Sonier answered 2020-02-16T22:42:43Z
6 votes

您可以加入任何表达式。 是否在数据库中定义外键无关紧要。 外键约束INSERT / UPDATE / DELETE,而不是SELECT。

那么,为什么许多项目都跳过定义外键? 有以下几个原因:

  • 数据模型设计不佳,需要破碎的引用(例如:多态关联,EAV)。

  • 编码人员可能听说过“外键很慢”,因此他们将其丢弃。 实际上,当您不依赖外键时,为确保数据一致性而要做的额外工作会使您的应用程序效率大大降低。 过早优化而没有实际衡量收益是一个普遍的问题。

  • 约束妨碍了一些数据清理任务。 有时,在重构数据时,您需要临时中断引用。 许多RDBMS允许禁用约束,但是有时程序员会决定更容易禁用它们。 如果经常需要禁用约束,则可能表明数据库设计严重受损。

Bill Karwin answered 2020-02-16T22:43:22Z
3 votes

您所描述的方式所使用的外键并非如何使用。 它们的目的是确保如果某个记录在逻辑上依赖于相应记录,则该其他位置确实存在。

我相信,如果开发人员/ dbas有时间(A)为他们的表和字段使用开发人员的好名字,或者(B)定义广泛的外键约束,则选项A是简单的选择。 我在两种情况下都工作过。 依靠广泛的约束来维持秩序并防止人们搞砸事情,这确实会变得一团糟。

在开发过程中要使所有外键约束保持最新状态需要花费大量的精力,您可能会花时间在其他几乎没有时间完成的高价值任务上。 相反,在具有良好命名约定的情况下,外键立即清晰可见。 开发人员不必查找外键,也不必尝试查询以查看其是否有效。 他们只看到关系。

我认为,随着使用数据库的不同团队数量的增长,外键约束会很快变得有用。 强制执行一致的命名变得困难; 对数据库的了解变得支离破碎; 数据库操作容易给另一个团队带来意想不到的后果。

Patrick Karcher answered 2020-02-16T22:43:57Z
3 votes

因为在实践中,理论还不够;)

认真地说,根据我的经验,主要是因为理论不够灵活,无法考虑您在现实世界中必须处理的所有可能性。 只有在一种非常奇怪的情况下,您必须将其存储在数据库中(或者更常见的情况,例如重载列),才需要退出FK并在DAL中实现它。

也许您可以开发一些可以以完全标准化的方式(例如)进行存档的解决方案,但是在许多情况下,所需的工作和/或最终结果不足以使您满意。

我的两分钱。

j.a.estevan answered 2020-02-16T22:44:31Z
2 votes

建立DBMS的目的是允许最广泛的解决方案,同时仍可按照其核心规则进行工作。

将联接限制为已定义的外键将极大地限制功能,特别是因为大多数开发不是通过专用DBA或对SQL /存储过程的检查而发生的。

话虽如此,根据您的数据访问层,可能会要求您配置外键以使用功能。 例如Linq to SQL。

Bravax answered 2020-02-16T22:45:01Z
2 votes

外键的使用不像关系理论所建议的那样频繁,因为DB /关系类型的人不会写太多的代码,甚至不会设计表。 程序员编写代码/设计表或对表的设计有很大影响。

ElGringoGrande answered 2020-02-16T22:45:21Z
2 votes

您使用哪种数据库应用程序? 您经常看到的理论是关于使用数据库原始数据的,在这种情况下,约束可能非常有用。 实际上,数据库通常用作大型应用程序的后端。 在许多情况下,这些应用程序必须自己验证事务,这会浪费精力在数据库中重复进行。

例如,考虑一个销售应用程序。 当有人输入订单时,它可能会在数据库中查找客户,以获取地址或信用卡信息。 当找不到客户时,将对其进行编程以进行合理的处理。 如果它一直等到尝试在订单表中插入一行以发现没有客户,就会得到较慢且较不方便的反馈。

必须维护数据库的完整性,但是在DBMS本身中进行操作并不总是最好的方法。

David Thornley answered 2020-02-16T22:45:51Z
1 votes

外键非常重要,尤其是在对它们进行手动查询或正在主动为其开发软件的数据库中。 在数据库上运行的每个未经测试的查询都有可能包含错误。 诸如外键之类的约束用于在将不一致引入数据之前突出显示这些错误。

这些约束由架构的设计人员应用,并确保数据保留在所设想的模型中。 如果约束不存在,则查询迟早会引入一些不一致之处。 不一致将导致查询结果无法预测,并且很难逆转。

Paul answered 2020-02-16T22:46:17Z
1 votes

自从关系数据库成为常态之前,我已经编程了几十年。 当我自学PHP时开始使用MySQL时,我看到了Foreign Key选项,最初的想法是“哇!那真是太迟了”。 原因仅仅是傻瓜认为实验室决定了现实。 显而易见,除非您编写的应用程序永远都不会改变,否则您将应用程序包装在钢铸件中,唯一的选择就是建立更多的表或提供创新的解决方案。

最初的评估是在我遇到的每个实际生产应用程序中产生的。 约束不仅大大减慢了所有修改的速度,而且几乎使应用程序的增长几乎不可能,而这是企业所需的。

我发现对表的任何约束的唯一原因是惰性编码器。 不愿意编写干净的代码来检查数据完整性。

麦可

Michael answered 2020-02-16T22:46:51Z
0 votes

好问题。 我一直想知道为什么SQL没有这样的语法

SELECT tbl1.col1, tbl2.col2
  FROM tbl1
  JOIN tbl2 USING(FK_tbl1_tbl2)

其中FK_tbl1_tbl2是表之间的一些外键约束。 这将比NATURAL JOIN或Oracle的USING(col1,col2)更加有用。

erikkallen answered 2020-02-16T22:47:16Z
0 votes

主要原因是大多数MySQL GUI工具(Navicat,MySQL等)中没有查询就无法设置它们。

听起来很愚蠢,但我也对此感到内since,因为我没有记住语法:/

Andrew G. Johnson answered 2020-02-16T22:47:40Z
0 votes

对我来说,部分原因是(是的,这是一个me脚的借口)MS的SQL Server Management Studio中用于添加外键的UI太糟糕了。

外键是“表a的x列中的任何值都必须出现在表b的y列中”的约束,但是在SSMS中指定它的UI不能清楚地表明您正在弄乱哪个表,即 父表,即子表,依此类推。

每次我必须创建一个外键时,都要反复尝试,直到它似乎可以使用为止。

Aric TenEyck answered 2020-02-16T22:48:10Z
-1 votes

我不知道会自动隐式连接所有外键表的SQL方言。 我已经看到用于报告推断的代码生成和数据字典工具,但是SQL始终是明确的。

这就是为什么您看到实际上在SQL中,所有联接都是显式的。

在实践中,没有FK约束的数据库往往会出现完整性问题,因为不存在要求密钥存在的约束。 因此,拥有尽可能多的约束当然是最佳实践-它保护完整性并帮助优化器和其他用户。 与任何最佳实践一样,知道何时(如果有)违反规则也很重要。

至于为什么可以建立一个与这些表之间的外键约束不匹配的联接,有无数的示例。 特别是在具有部分联接的组合键的情况下,我发现这通常是必要的。 我们经常在数据仓库中使用表主键的部分版本来联接表。

您可能还对本文有关优化程序消除外键联接的文章感兴趣。

Cade Roux answered 2020-02-16T22:48:49Z
-2 votes

外键是耦合。 在编程中,耦合很少是好的。

datasn.io answered 2020-02-16T22:49:09Z
translate from https://stackoverflow.com:/questions/1876013/why-are-foreign-keys-more-used-in-theory-than-in-practice