关系数据库中的约束-为什么不完全删除它们?


20

如今,是否有任何理由在表之间(在SQLserver内部)建立约束?如果是这样,什么时候?我所在领域的大多数应用程序都是基于对象原理构建的,并且可以按需将表连接在一起。需求基于应用程序的需求。我不会加载一堆受约束的表来进行简单的查找,而这些查找又又(在执行操作之后)需要进行另一个简单的查找。

诸如EntityContext,Linq2Data,NHibernate之类的ORM工具也可以自己处理约束,至少您知道哪些表需要彼此使用。在服务器内部进行约束仅是对相同的更改进行两次(强制执行)?

通常这不是要决定的问题,但是此数据库的设计却大不相同。设计看起来很正常,主要是镜像应用程序使用的对象。令我困扰的是在SQLserver内部使用“非级联”配置的所有约束。这意味着在编码新的数据库查询时,您必须扮演“寻找并查找”的角色。在某些情况下,单个订单最多需要10个级别的确切订单。

这让我感到惊讶,我不确定如何处理。

在我的简单世界中,这种设置使约束失去了大部分目的。如果在不了解设计的情况下从主机访问数据库,则单击“确定”。

在这种情况下,您将如何行动?
为什么不从db中删除所有约束并将它们保持在应用程序级别呢?


6
您打算始终通过单个ORM工具访问数据吗?还是您打算让“乐趣”在使用中的每个ORM工具中正确复制所有约束?
Donal Fellows,

1
根据我对彼得的最新评论,我必须同意。将所有约束都依赖于代码库(并将其从db中删除)的观点非常狭窄,并且可能完全适用于短期应用程序。可能也适用于某些RAD开发人员/项目。
独立时间:

4
次要nitpick:当您将表之间的外键连接称为“关系”时,我认为这会造成一些混乱。关系数据库中的“关系”是表本身,而不是连接。尤其是当我们继续谈论“关系设计”时-是表还是表外键?
Thomas Padron-McCarthy

谢谢。我将“表之间的连接”称为约束。因此,您可能正确地看到了有关表设计原理(表结构)的“关系数据库”。当涉及到“关系与对象”数据库时,更准确的描述将是“设计模式”。
独立时间:

1
您的数据库将超过您的应用程序代码。另外,您的ORM损害了您的应用程序性能,并且很有可能最终至少在某些用例中最终想要绕过它。如果您现在不知道,那么最终您将知道。samsaffron.com/archive/2011/03/30/…。此外,删除所有约束后,当数据库被您的其他应用程序滥用时,数据库完全无法保护自己的完整性,这可能是从另一个实际应用程序到使用Excel执行的执行程序。
克雷格2014年

Answers:


46

不从DB中删除约束的两个一般原因:

  • 现在或将来可能会有更多应用程序使用或不使用ORM 来访问它。即使这些应用程序的开发人员忠实地复制了那里的所有约束(使用较低级别的非ORM解决方案可能会更加困难),但这始终是额外的工作。如果不是这样,即使是很小的疏忽也足以破坏架构的完整性 ……这是您不想冒险的事情。在大多数公司中,存储在数据库中的数据是其业务的命脉,因此,必须以任何方式确保其完整性。实现这一目标的久经考验的最佳方法是在数据库中实现尽可能多的约束。
  • 查询优化器在很大程度上取决于数据库级别的约束。如果删除约束,查询性能可能会开始下降。您可能不会立即注意到它,但是有一天它会击中您,到那时可能已经太晚了,很难轻松修复它。事情的本质是,在峰值负载时间,数据库性能往往会崩溃,这是最不可能进行仔细,深思熟虑的设计改进,并辅之以精确的性能测量和详细分析以查明根本原因。

您的具体案例听起来像是DB模式可能最初是由ORM工具生成的(或由对关系领域不太有经验的人设计的),所以从关系的角度来看它不是最佳的。最好将其分析并改进为更“自然”的关系设计,同时使其与ORM视图保持一致。让数据库专家参与此分析可能会很有用。


5
@Jonas,然后与他讨论有关DB设计的感知问题。关系和面向对象是两个不同的世界,它们本身都不是对另一个的“改进”,两者都有自己的位置。按照关系原理设计C#应用程序与通过OO方法设计数据库一样是一个大错误。
彼得Török

3
@Jonas,反映您的更新:如果您需要编写过于复杂的查询以针对数据库模式实现看似简单的事情,则可能是数据库设计不足以达到其目的的信号-或您不够熟练(请不要冒犯,在您的帖子中并不能证明您对SQL的使用经验。作为免责声明,我本人还远不是专家。)
PéterTörök

1
我可能需要学习一些表达方式,以使自己易于理解:)。我重新阅读了问题和答案,并且不得不逆转。毫无疑问,将DB作为所有约束的主要方面是很重要的。所有系统都需要以此为基础进行设计。一个非常狭窄的观点认为代码库可以完成工作。如果每个系统都可以对约束做出自己的决定,那么最终将以错误的建议关系和孤立的整个表的形式出现在一个高手。如果不是现在,则稍后会与其他编码器一起发生。
独立

8
“现在或将来,可能会有更多的应用程序访问它。” 更不用说一些数据库管理员,在用户等待时运行原始SQL查询来解决数据库问题……
Thomas Padron-McCarthy

5
+1:如果db正在存储业务数据(而不仅仅是应用程序配置等),那么数据库将在当前应用程序之外进行实时发布或扩展的可能性接近100%
Binary Worrier

27

应用程序可以来去去去,但数据永远存在。在我的公司中,DB已有30-40年的历史,只要公司存在,它就会一直存在。应用程序发生变化,开发人员来来往往。最好具有完整性和良好的逻辑数据模型。这样,某人可以查看数据并获得有意义的理解,而无需经历复杂的代码库。这也有助于显着报告。应用程序也可以并且会存在错误,并且数据库约束可以防止这种情况。我的默认位置是尽可能多地约束(FK和检查)。
没有约束的唯一原因是,如果您的设计模式不允许这样做,例如逐层或性能问题。


我会说,您在这里提出了非常明智的建议。我的观点可能更适合RAD开发或任何应用程序使用寿命短的开发-仅出于最小化开发时维护的考虑。
独立时间:

15

令我困扰的是在SQLserver内部使用“非级联”配置的所有约束。

这不打扰我,这意味着有人表现出了良好的意识。级联删除通常对数据库非常不利。首先,如果您在相关表中有数据,有时您希望删除失败。例如,如果您有一个过去有订单的客户,则不希望删除该客户,或者丢失有关订单对象的数据,而级联删除操作将摆脱记录,这将使您的财务报告混乱。

您似乎认为轻松发展是最重要的。在数据库世界中,这根本不是事实。数据完整性是最重要的事情,其次是性能和数据安全性。如果编写查询需要更长的时间,那就这样吧。

通常,数据库由许多应用程序作用:一个或多个网站或桌面应用程序,报告应用程序,Web服务,查询窗口,ETL流程等。如果不在数据库级别强制实施约束,则首先会失去完整性数据,因为这些应用程序之一可能并不遵循所有规则。其次,如果您决定以后使用其他应用程序,则必须多次编码这些约束并重写它们。第三,您无法预先控制是否需要执行某种不会通过应用程序执行的数据维护任务(例如修复来自不良客户数据导入的数据或更改来自一个客户端的所有10,000,000条记录竞争对手收购该公司后将其转让给其他客户)。通常,应用程序开发人员不会


谢谢你的答复。您所讨论的所有过程和应用程序类型都应与DAL(后者将包含约束)进行对话。但!您的观点很完美,您的评论很好。旁注:是的。我倾向于尝试缓解发展的方法。对我来说,减少复杂性可以减少犯错的方法。即使处理不当,这也不是“希望开发得更容易/更快”。因此,为什么我要发布这个问题!如果这个非级联选择是有理智的,而不是在这种情况下是100%,那么我也会看到一个很好的感觉。我必须找出原因。
独立

@Jonas,也可能有性能原因。取决于子记录的数量。如果要删除小型组,但是可以触发数百万条记录,则可以,最好是进行批处理,而不要在整个过程进行时锁定所有表。通常,由于这种原因,许多dbas都不允许级联删除,因为如果删除影响太多记录,它可以锁定生产系统。
HLGEM

2
并非所有进程都不应与DAL通信。ETL流程通常不会发生,也不需要在数据库级别发生的事情会在发生一些大的更改时影响很多记录(例如,客户被收购)。您也不能禁止任何人使用查询窗口进行一次性更改。我从未见过没有在数据库级别没有强制使用constraits的数据库,而随着时间的推移,constrait没有出现完整性问题。
HLGEM 2011年

10

我在某处读到一个基本上说过的话:数据是您应用程序的关键。如果要通过你的UI永远只能访问数据(我的意思是有史以来,在现在和将来,为所有永恒...或者你的应用程序的生命周期,反正),那么你就不需要数据库的约束。但是,除了应用程序本身之外,还有可能需要触摸数据,例如Web服务,公共API,Rake Task / SQL Job / cron / automated script,那么您将为自己节省很多潜在的麻烦。通过保持数据库约束的方式。

我坚信这是软件开发的一个领域,你应该适用DRY(我满以为downvotes的该语句一群)。您的数据是应用程序的核心和灵魂-如果数据一旦损坏就无法修复,那就结束了。IMO在所有需要的地方执行约束都是值得的。如果这意味着以数据库级别的触发器和约束,中间件上的服务器端验证以及UI上的客户端Javascript(针对Web应用程序)的形式出现,则IMO必须确保数据始终保持原始状态。


6

您知道ORM是什么意思吗?对象关系映射。引用维基百科“在不兼容的类型系统之间转换数据的技术”。是的,关系模型和对象模型不能一起使用。通过尊重两个类型系统的规则,ORM进行了很好的转换。RDBMS的组织方式使您可以通过使用约束来实现数据完整性。通常,完整性非常好,因此ORM在创建用于存储对象数据的数据模型时倾向于使用它们。您的ORM可能有充分的理由使用“非级联”约束。并且,如果这迫使您进行复杂的查询,而不仅仅是创建/更新/删除某些对象,则您的ORM设置有问题。

如果您认为关系概念很烦人,那么为什么不使用对象数据库呢?一段时间以前,它们运行缓慢(这就是为什么大多数人仍然使用RDBMS的原因),但是据我所知,情况有所改变。您将摆脱所有的关系壁垒。只是对象进入,对象离开。


主题是关于从数据库中移出约束功能,并依赖于代码库中的设置/开发(例如,.net语言:Entity / Linq2Sql)。
独立

是的,我知道,但是我的意思是,您首先需要了解为什么首先存在约束,然后为什么放弃约束可能不是一个好主意。
Jacek Prucia

感动!不掉线。我了解您对这个问题的了解感到遗憾,而这并不是您要的。
独立

您实际上无法在不兼容的系统之间移动任何东西。您将删除数据库约束,引入应用程序约束,只是希望它们能够相同地工作(事实可能是假的)。无论如何,如果我误解了你的问题,我的真诚的谢意。
Jacek Prucia

谢谢!“移动”是指文学上的“移动”。这意味着您在每个系统上创建(良好表达)应用程序约束。至少每个不能共享相同DAL的系统。一个很好的例子是来自数据库管理员的直接查询,它“修复了某些问题”。没有数据库约束和缺乏设计知识会导致孤立的数据或完全模拟的数据。
独立

6

嗯,这就是eBay所做的,他们可能拥有世界上最大的数据库之一:

http://www.dba-oracle.com/oracle_news/news_ebay_massive_oracle.htm http://www.addsimplicity.com/downloads/eBaySDForum2006-11-29.pdf

尽管上面已经说过通过引用完整性来提高性能,但是实际上它可能会降低;这就是为什么大型数据库一直放弃其约束并在应用程序层中进行工作的原因。据我所知,这是唯一真正的好理由。

通过消除这些约束,您实际上会失去安全网,从而保持数据干净,并带来自身的问题。因此,与所有事物一样,这是一种平衡行为。我认为总体上保持参照完整性是正确的选择。

在具有强大的引用完整性的开发环境中工作后,我知道从开发人员的角度来看,这可能会很痛苦。通常在开发环境中,脏数据并不重要,解决删除行的方法可能需要一个小时或更长时间。但是,它也非常有用,因为约束使架构变得明确。


终于有人了解我:-)。您完全正确,这里的平衡点很重要。如果作为战略重点,将约束移到应用程序级别可能是安全的选择。由于强大的约束/完整性,某些URL可以证明站点性能下降,这很好。
独立时间:

10
是的,不要忘记- 不要忘记 -像Facebook和Amazon这样的Ebay比99.99%的数据库大千亿倍,而对他们有好处的数据库可能与对数据库有好处的数据库大不相同。
托尼·安德鲁斯

2
以及eBay,Facebook,Amazon可能不会在财务和会计软件,清单软件,人力资源数据或不丢失数据至关重要的任何地方使用不受限制的数据库。
HLGEM 2011年

2
如果您有足够的时间,专业知识和金钱,您最终可以对任何RDBMS,Web服务器或操作系统进行编程以满足特定需求。
JeffO

1
直到他们处理的海量数据基本上超过了数据库服务器的处理能力,eBay才开始这样做,并且他们有数百万美元投资于新架构。如果您每天要进行数十亿笔交易,那么一定要努力消除约束,并转而使用完全基于队列的无交易,可大规模扩展的系统,例如eBay。否则,请不要低估数据库服务器,也不要通过消除所有约束来使数据库遭受数据损坏。
克雷格2014年

4

首先-我的回答:不,您不应该仅依靠应用程序来管理数据。

这指向了一个更大的辩论:ORM鼓励人们不屑于“直接” DB交互,这通常以牺牲标准化/参照完整性为代价。将表强制映射到任意对象层次结构,但要以隐含在关系模型中的设计为代价。OOP偏爱的去耦在这里可以说是牺牲了,因为应用程序使它在数据结构中感觉到了设计。尽管ORM已显示出巨大的实用性,但它似乎是基于对SQL的滥用或不信任。

(重新)出现了新的范例,例如功能编程。如果开发团队决定采用一种新的编程方法,那么这对于根据ORM的要求构造的数据有什么影响?

我同意@Jacek Prucia的观点-我认为ORM对于RDBMS来说是一个糟糕的选择,我个人选择在RDBMS上使用DBAL,或者选择使用ORM的OODB。


+1表示该主题的替代方法。辩论的另一面当然是:“某些数据有多糟糕?” 答案可能是取消交易或向某人的百万美元银行帐户注资数十亿美元。以及通过良好的清理例程删除的一些孤立数据。该主题的摘要看起来像灵活性成本的一致性。而这又完全取决于数据库内容和使用的严重性。
独立

3

约束是您在数据库级别具有一致性和数据完整性的唯一保证。当然,您可以使用应用程序代码强制执行约束,但是如果将来需要直接修改数据怎么办?您可能了解如何维护数据完整性,但其他人则可能不了解。将约束保持在数据级别可确保即使有人在他们不了解的地方闲逛时也能确保完整性。

此外,假设您的应用程序需要重写,但要使用相同的数据库。代码中的所有这些限制只是在乞求一些错误,这些错误会阻止某些条目进入,同时允许错误数据通过。

开发时,请保持简单。约束使您可以做到这一点。(也就是说,当约束引发错误时,请不要向用户吐出相同的错误。使错误易于理解。)

(关于级联问题:这是一件好事。我宁愿抛出一个错误,指出必须先删除某些其他记录,而不是依靠级联才能使所有事情都正确。级联理论上很好,但不一定所以在实践中。)


2

数据库中的约束的一个问题是,它们为程序提供了有关失败原因和解决方法的有限信息。这意味着,为了进行平滑处理,通常需要在应用程序中重复进行约束检查,因此浪费了数据库约束检查。

这冒着损害数据完整性的风险,因此我们在这里进行了权衡。对于重要数据,确保数据完整性几乎总是比性能更重要,即使事务看起来是任意的,也要使事务失败比弄乱数据要好得多。

为了安全地删除约束,因此确保数据库访问的安全至关重要,因此如果不检查约束就无法更改数据库。当编写新的应用程序或提出临时的数据处理方式时,这是不可靠的,因为这仅是一个错误,并且数据库已损坏。

因此,为了免除数据库约束,必须预先确定数据库可以做什么和不能做什么,以便可以广泛地编写,检查和测试所有应用程序。必须预先建立所有数据库要求,对数据库要求的任何更改都将需要大量的工作。这是一种冻结瀑布方法,仅在非常特殊的情况下有效。(根据需求进行设计,实施和维护就像在水上行走一样。必须先冻结某些东西,如果冻结得不够充分,则结果可能是灾难性的。)

确实起作用的一个例子是大型企业应用程序,例如PeopleSoft和SAP,其中该应用程序实际上已经执行了所有操作,并且有精心定义的扩展方法。还有其他非常罕见的可能性。

因此,除非您从事大型企业项目(而且我不想这么做)或可以走水,否则将这些约束留在数据库中。


1
谢谢你的答复。约束将在该项目的数据库中!我完全相信:)。在决定将来的项目以及与其他部分的讨论时,我也会有更广阔的视野。
独立时间:

1
还应考虑到没有限制,您将其留给应用程序代码本身来检测它是否被破坏了。这就是侵犯您的示例中的约束,顺便说一句,从数据不一致或损坏保存在数据库中的约束应用程序代码。顺便说一句,使用约束也不会自动意味着性能降低,并且不使用约束会使数据库暴露在外,因此无法保护自己。
克雷格
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.