为什么外键在理论上比在实践中更多?

时间:2009-12-09 18:50:50

标签: sql database foreign-keys

当你研究关系理论时,外键当然是强制性的。但实际上,在我工作的每个地方,表产品和连接总是通过在查询中明确指定键来完成,而不是依赖于DBMS中的外键。

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

为什么你认为那是? DBMS是否应该强制只使用外键来创建联接和产品?

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

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

17 个答案:

答案 0 :(得分:39)

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

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

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


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或Postgres with PostGIS。您将能够执行以下查询:

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

来源:ConceptDev - SQL Server 2008 Geography: STIntersects, STArea

您可以在“Sql 2008 query problem - which LatLong’s exists in a geography polygon?”帖子的已接受答案中看到另一个类似的地理空间示例:

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连接,在实践中仍然有用。

答案 1 :(得分:34)

外键与联接的关系不如保持数据库完整性。证明这一点就是你可以以任何你想要的方式加入表格,即使是不一定有意义的方式。

答案 2 :(得分:10)

  

我无法想象需要按非FK字段连接表格。有人能给出一个有意义的例子吗?

如果FOREIGN KEY模型的实体之间的关系用关系模型中两个关系之间的等值连接反映,

ER只能用于强制引用完整性。

这并非总是如此。

以下是我前一段时间写的博客文章中的一个例子:

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

这是模型的关系实现:

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

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

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

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模型,但是在这些关系之间不能声明外键,因为用于绑定它们的操作不是等值连接。

答案 3 :(得分:8)

不,执法是不必要的;它会禁止一些有用的功能,例如可能的列重载。虽然这种用途并不理想,但它在某些现实世界中很有用。

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

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

答案 4 :(得分:6)

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

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

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

  • 编码员可能听说“外键很慢”,所以他们放弃了。实际上,当您不能依赖外键时,为确保数据一致性而必须做的额外工作会使您的应用程序效率降低。在没有实际测量效益的情况下过早优化是一个常见问题。

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

答案 5 :(得分:3)

以您描述的方式使用的外键不是它们的使用方式。它们的目的是确保如果记录在逻辑上依赖于其他地方存在的相应记录,那相应的记录确实存在。

我相信如果开发人员/ dbas有时间(A)开发人员的表和字段的良好名称,或(B)定义广泛的外键约束,选项 A 是容易的选择。我在两种情况下都工作过。如果依靠广泛的限制来维持秩序并防止人们搞砸事情,那么事情真的会变得一团糟。

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

我认为随着使用数据库增长的不同团队数量的增长,外键约束很快就会变得有用。执行一致的命名变得困难; DB的知识变得支离破碎; db操作很容易对另一个团队产生意想不到的后果。

答案 6 :(得分:3)

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

说真的,根据我的经验,主要是因为理论不够灵活,无法考虑你在现实世界中必须处理的所有可能性。只有一个非常奇怪的情况,你必须存储在你的数据库(或更常见的东西,如重载列),你必须离开FK并在DAL中实现它。

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

我的两分钱。

答案 7 :(得分:2)

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

例如,考虑销售应用程序。当有人输入订单时,它可能会在数据库中查找客户,以获取地址或信用卡信息。当它找不到客户时,它将被编程为做一些合理的事情。如果它一直等到它试图在订单表中插入一行来发现没有客户,那么它会变得更慢,反馈也不那么方便。

某些东西必须保持数据库的完整性,但在DBMS内部进行并不总是最好的方法。

答案 8 :(得分:2)

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

答案 9 :(得分:2)

DBMS的构建允许最广泛的解决方案,同时仍然按照其核心规则工作。

将连接限制为已定义的外键会极大地限制功能,尤其是在大多数开发不会出现在专用DBA或查看SQL /存储过程的情况下。

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

答案 10 :(得分:1)

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

这些约束由架构的设计者应用,它们确保数据保留在他设想的模型中。如果不存在约束,那么查询迟早会引入一些不一致。不一致会导致查询产生不可预测的结果,并且很难逆转。

答案 11 :(得分:1)

我已经编程了几十年,因为在关系数据库成为常态之前。当我第一次开始使用MySQL时,我自学PHP,我看到了外键选项,第一个想法是“哇!那是迟钝的。”原因只是傻瓜认为实验室决定了现实。很明显,除非您编写的应用程序永远不会被永远更改,否则您将应用程序包装在钢管中,唯一的选择是构建更多表格或出现有创意的解决方案。

这个初步评估已经在我遇到的每一个真实世界的生产应用程序中诞生。这种约束不仅会显着降低任何和所有修改的速度,而且使得应用程序的增长几乎不可能,这对于企业来说是必需的。

我找到桌子上任何约束的唯一原因是懒惰的编码器。不愿意编写干净的代码来检查数据的完整性。

迈克尔

答案 12 :(得分:0)

好问题。我一直想知道为什么SQL没有类似

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

其中FK_tbl1_tbl2是表之间的一些外键约束。这对于NATURAL JOIN或Oracle的使用(col1,col2)非常有用。

答案 13 :(得分:0)

主要原因是在大多数MySQL GUI工具(Navicat,MySQL等)中无法在没有查询的情况下进行设置。

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

答案 14 :(得分:0)

对我来说,部分原因是(并且是的,这是一个蹩脚的借口)MS的SQL Server Management工作室中用于添加外键的UI是糟糕

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

每次我必须创建一个外键时,它一直是反复试验,直到看起来有效。

答案 15 :(得分:-1)

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

这就是为什么你在实践中看到SQL,所有联接是明确的。

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

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

您可能也对this article感兴趣的优化器消除外键连接感兴趣。

答案 16 :(得分:-2)

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