为什么外键在理论上比实践中更多?
当你研究关系理论时,外键当然是强制性的。 但实际上,在我工作的每个地方,表格产品和连接总是通过在查询中明确指定键来完成的,而不是依赖DBMS中的外键。
这样,当然可以按字段join两个表,这些字段不是外键,会产生意想不到的结果。
你为什么这么认为? DBMSs不应该强制连接和产品只能通过外键进行吗?
编辑:感谢所有的答案。 现在很清楚,FK的主要原因是参考完整性。 但是如果你devise一个数据库,模型中的所有关系(ERD中的IE箭头)至less在理论上会成为外键,无论你在数据库pipe理系统中如何定义它们,它们在语义上都是FK。 我无法想象需要通过不是FK的字段来连接表。 有人可以举一个有意义的例子吗?
PS:我意识到N:M关系成为单独的表而不是外键的事实,为简单起见,只是省略了它。
外键约束存在的原因是为了保证引用的行存在。
“外键标识一个表中引用另一个表中的一列或一组列的列或一组列。引用列的一行中的值必须出现在引用表中的单个行中。
因此,引用表中的行不能包含引用表中不存在的值(可能为NULL)。 通过这种方式可以将信息链接在一起,这是数据库规范化的一个重要部分。“( 维基百科 )
RE:你的问题:“我不能想象需要通过非FK字段来连接表”:
定义外键约束时,引用表中的列必须是被引用表的主键,或者至less是候选键。
在进行连接时,不需要连接主键或候选键。
以下是一个有意义的例子:
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;
另外一种情况是这些连接是有意义的,就是在提供地理空间function的数据库中,比如SQL Server 2008或Postgres与PostGIS。 你将能够做这样的查询:
SELECT state, electorate FROM electorates INNER JOIN postcodes on (postcodes.Location.STIntersects(electorates.Location) = 1);
来源: ConceptDev – SQL Server 2008地理:STIntersects,STArea
您可以在“ Sql 2008查询问题 – LatLong存在于地理多边形中 ”的post的接受答案中看到另一个类似的地理空间示例:
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连接,与外键和候选键无关,在实际中仍然可以使用。
与保持数据库完整性相比,外键与连接关系更less。 certificate这一点的是,你可以以任何你想要的方式连接表,即使这些方式不一定是合理的。
我无法想象需要通过不是FK的字段来连接表。 有人可以举一个有意义的例子吗?
如果ER
模型的实体之间的关系反映为关系模型中两个关系之间的等价关系,则FOREIGN KEY
只能用于强制执行参照完整性。
这并非总是如此。
以下是我前一段时间撰写的博客文章中的一个例子:
- 什么是实体关系模型?
该模型描述货物和价格范围:
这里是模型的关系实现:
CREATE TABLE Goods (ID, Name, Price) CREATE TABLE PriceRange (Price, Bonus)
如您所见, PriceRange
表只有一个与价格相关的属性Price
,但该模型有两个属性: EndPrice
和EndPrice
。
这是因为关系模型允许转换集合,并且可以使用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模型,但是在这些关系之间没有外键可以被声明,因为用来绑定它们的操作不是等价的。
不,执法是不必要的。 它会禁止一些有用的function,如可能的重载列。 虽然这种使用方式并不理想,但在一些现实世界的情况下是有用的。
外键约束的恰当使用就是这样; 对添加到给定列的值进行约束,以确保所引用的行存在。
应该指出的是,在给定模式上显着缺乏外键约束是一种不好的“气味”,并且可能表明一些严重的devise问题。
你可以join任何表情。 无论您是否在数据库中定义外键都不重要。 外键约束INSERT / UPDATE / DELETE,而不是SELECT。
那么为什么大量的项目会跳过定义外键呢? 有几个原因:
-
数据模型devise不佳,需要打破引用(例如:多态关联,EAV)。
-
编码者可能听说过“外键慢”,所以他们放弃了。 事实上,当你不能依赖外键时,为确保数据一致性所做的额外工作使得你的应用程序效率低下。 不实际测量效益的过早优化是一个常见问题。
-
限制妨碍了一些数据清理任务。 有时您需要在重构数据时临时中断引用。 许多RDBMS允许禁用约束,但是有时候程序员决定让它们更容易被禁用。 如果经常需要禁用约束,这可能表示数据库devise严重破坏。
用你描述的方式使用的外键不是它们的意思。 他们的目的是确保如果一个logging在逻辑上依赖于相应的logging存在于其他地方,则相应的logging确实存在。
我相信,如果开发人员/ dbas有时间(A)开发人员的表名和字段名称,或者(B)定义广泛的外键约束,则选项A是一个简单的select。 我在两种情况下工作。 如果要依靠广泛的约束来维持秩序,防止人们搞砸事情,那么真的会变成一团糟。
在开发过程中需要花费很多精力来保持所有的外键约束都是最新的,这样你就可以花费在其他几乎没有时间的高价值任务上。 相反,在你有良好的命名约定的情况下,外键是立即清除。 开发人员不必查找外键,或尝试查询是否有效; 他们只能看到关系。
我认为,随着不同团队使用数据库的数量不断增长,外键约束很快就会变得有用。 变得难以执行一致的命名; DB的知识变得分散; 数据库操作很容易对另一个团队产生意想不到的后果。
因为在实践中,理论是不够的;)
严重的是,根据我的经验,主要是因为理论不够灵活,无法考虑在现实世界中必须处理的所有可能性。 只有一个非常奇怪的情况下,你必须存储在你的数据库(或更常见的东西,如超载列),你必须走出FK并在DAL中实现它。
也许你可以开发一些解决scheme,以完全标准化的方式归档(例如),但是在很多情况下,所需的工作和/或最终的结果是不值得的。
我的两分钱
数据库pipe理系统的构build是为了允许最广泛的解决scheme,同时依照其核心规则进行工作。
限制连接到定义的外键会极大地限制function,特别是大多数开发不会发生在专用的DBA或SQL /存储过程审查中。
话虽如此,根据您的数据访问层,您可能需要configuration外键,才能使用function。 例如Linq to SQL。
因为DB /关系types的人不会写很多代码甚至devise表,所以外键的使用并不像关系理论所build议的那么频繁。 程序员编写代码/devise表或者对表的devise有很大的影响。
你在做什么样的数据库应用程序? 你经常看到的理论是关于使用原始数据库,在这种情况下,约束是非常有用的。 在实践中,数据库通常用作较大应用程序的后端。 在很多情况下,这些应用程序必须自行validation事务,并且在数据库中重复这个操作是浪费时间的。
例如,考虑销售应用程序。 当有人input订单时,可能会在数据库中查找客户,以获取地址或信用卡信息。 当它没有find一个客户,它会被编程做合理的事情。 如果一直等到试图在订单表中插入一行来发现没有客户,那么反馈会变得越来越慢。
有些东西必须保持数据库的完整性,但在DBMS内部进行并不总是最好的方法。
外键非常重要,尤其是在手动查询数据库或者正在为其开发软件的情况下。 数据库上运行的每个未经testing的查询都可能包含错误。 在将不一致性引入数据之前,诸如外键之类的约束用于突出显示这些错误。
这些约束由模式的devise者应用,并且确保数据保留在他设想的模型中。 如果约束不存在,那么查询迟早会引入一些不一致。 不一致将导致查询结果不可预测,而且很难扭转。
我已经编程了几十年,因为在关系数据库成为常态之前。 当我自学PHP的时候,第一次开始使用MySQL时,我看到了Foreign Key选项,第一个想法是“哇!这是迟缓的”。 愚蠢的原因是认为实验室决定了现实。 很明显,除非你编写了一个永远不会被改变的应用程序,否则你正在将你的应用程序包装在一个钢pipe中,唯一的select是build立更多的表格或者提出创造性的解决scheme。
这个初步的评估已经出现在我遇到的每一个真实的生产应用中。 约束不仅显着减慢了所有的修改,而且使应用程序的增长几乎不可能,这是业务所需要的。
我发现的任何约束表的唯一原因是懒惰的编码器。 不愿意编写干净的代码来检查数据的完整性。
迈克尔
好问题。 我一直想知道为什么SQL没有类似的语法
SELECT tbl1.col1, tbl2.col2 FROM tbl1 JOIN tbl2 USING(FK_tbl1_tbl2)
其中FK_tbl1_tbl2是表之间的一些外键约束。 NATURAL JOIN或Oracle的USING(col1,col2)将会非常有用。
主要原因是在大多数MySQL GUI工具(Navicat,MySQL等)中没有查询就没有办法设置它们,
听起来很愚蠢,但我对此也感到内疚,因为我没有记忆的语法:/
其中一部分对我来说就是(是的,这是一个蹩脚的借口)MS的SQL Serverpipe理工作室用于添加外键的用户界面非常糟糕 。
外键是一个约束:“表格a中的列x上的任何值必须出现在表格b中的列y上”,但是用于在SSMS中指定它的UI并不能清楚地指出你正在处理哪个表格,父表,这是子表,等等。
每次我不得不创build一个外键,直到它似乎工作,这是试错。
我不知道一个SQL方言隐式地自动连接所有外键表。 我已经看到代码生成和数据字典工具报告推断他们,但SQL总是显式的。
这就是为什么你看到,在实践中,在SQL中, 所有的连接是明确的。
在实践中,没有FK约束的数据库往往具有完整性问题,因为不存在要求密钥存在的约束。 所以,尽可能多的限制条件是最好的做法 – 它保护完整性,并帮助优化器和其他用户。 像任何最佳实践一样,知道什么时候(如果曾经)打破规则也很重要。
至于为什么你可以在这些表之间build立一个不符合外键约束的连接,有很多例子。 特别是在部分连接的复合键的情况下,我发现这往往是必要的。 我们经常使用数据仓库中主键的部分版本join表。
您可能还会对优化器的外键join消除感兴趣。
外键是耦合 。 在编程中,耦合很less。