什么是更好的数据库devise:更多的表或更多的列?
一位前同事坚持说,一个数据库比较多的表格,每个表格的列数less于每个表格的数据库比较less,而每个表格的列数都要多一些。 例如,而不是名称,地址,城市,州,邮编等列的客户表,您将有名称表,地址表,城市表等。
他认为这个devise更高效和灵活。 也许它更灵活,但我没有资格评论它的效率。 即使效率更高,我认为增加的复杂性可能会超过这些收益。
那么,对于列数越来越less的表,而对于列数越来越less的表,有没有什么好处呢?
在devise数据库时,我遵循一些相当简单的规则,我认为这可以用来帮助做出这样的决定….
- 青睐正常化。 非规范化是一种优化forms,具有所有必要的权衡,因此应该以YAGNI的态度来对待。
- 确保引用数据库的客户端代码与重构的架构足够分离,不需要重新devise客户端。
- 当它为性能或查询复杂性提供明确的好处时,不要害怕去规范化。
- 在数据量和使用情况允许的情况下 ,使用视图或下游表来实现非规范化,而不是非规范化模式的核心。
这些规则的通常结果是,初始devise将优先于列的表,重点在于消除冗余。 随着项目的进展和非规范化点的确定,总体结构将朝着兼顾冗余和列扩散的平衡发展,以换取其他有价值的好处。
我会争取赞成更多的表格,但只能达到某一点。 使用你的例子,如果你把用户的信息分成两个表,比如USERS和ADDRESS,那么你可以灵活地为每个用户分配多个地址。 一个明显的应用是具有单独的账单和送货地址的用户。
支持build立一个单独的CITY表的理由是你只需要存储一个城市的名字,然后在需要的时候引用它。 这确实减less了重复,但在这个例子中,我认为这是过度的。 这可能会更节省空间,但是当您从数据库中select数据时,您将通过连接支付价格。
这听起来不像一个关于表/列的问题,而是关于正常化的问题。 在一些情况下,具有高度的标准化 (在这种情况下“更多的表格”)是好的,干净的,但是通常需要大量的JOIN来获得相关的结果。 如果数据量足够大,这可能会使性能下降。
Jeff就StackOverflow的devise写了一些关于它的内容。 另请参阅Dare Obasanjo的 Jeff的链接。
完全标准化的devise(即“更多表”)更灵活,更易于维护,避免数据重复,这意味着您的数据完整性将更容易实施。
这些是正常化的强有力的理由。 我会select首先进行标准化,然后在您看到性能成为问题后才对规格化表进行规格化。
我的经验是,在现实世界中,即使使用非常大的数据集,也不会达到非规范化的地步。
这取决于你的数据库风格。 例如,MS SQL Server倾向于select较窄的表格。 这也是更“正常化”的方法。 其他引擎可能会更喜欢它。 大型机倾向于属于这一类。
每个表只应包含与主键唯一标识的实体有关的列。 如果数据库中的所有列都是同一实体的所有属性,那么只需要一个包含所有列的表。
但是,如果任何列可能为空,则需要将每个可为空的列置于其自己的表中,并使用外键将其置于主表中以对其进行标准化。 这是一个常见的情况,所以对于一个更清洁的devise,您可能希望将列添加到现有表中。 而且,通过将这些可选属性添加到自己的表中,它们不再需要允许空值,并且避免了与NULL有关的问题。
多表数据库是非常灵活的,如果任何这些一对一的关系在未来可能成为一对多或多对多。 例如,如果您需要为某些客户存储多个地址,那么如果您有客户表和地址表,则会更容易。 我不能真正看到你可能需要复制地址的某些部分而不是其他地址的情况,所以单独的地址,城市,州和邮政编码表可能有点过分。
像其他一切:这取决于。
列数与表计数没有硬性规定。
如果你的客户需要有多个地址,那么一个单独的表格是有道理的。 如果你有一个很好的理由将城市列标准化到自己的表中,那么也可以这样做,但之前我没有看到过,因为它是一个自由的表单字段(通常)。
桌子很重,标准化的devise在空间方面是有效率的,并且看起来“教科书很好”,但是可以变得非常复杂。 它看起来不错,直到你必须做12个连接才能得到客户的姓名和地址。 在最重要的性能方面,这些devise并不是自动的 :查询。
尽可能避免复杂性。 例如,如果一个客户只能有两个地址(不是任意多的),那么把它们全部放在一个表(CustomerID,Name,ShipToAddress,BillingAddress,ShipToCity,BillingCity等)中是有意义的。
这是杰夫的主题。
使用较less列的表格有好处,但是您还需要查看上面的场景并回答以下问题:
客户可以有多个地址? 如果不是,则不需要单独的地址表。 如果是这样,那么单独的表就会变得很有帮助,因为您可以根据需要轻松地添加更多的地址,在表中添加更多的列变得更加困难。
我会考虑作为第一步正常化,所以城市,县,州,国家会更好作为单独的列…… SQL语言的力量,与今天的DBMS-es允许您稍后分组您的数据,如果您需要查看它在一些其他的,非正常化的看法。
当系统正在开发中时,如果你认为这是一种改进,你可能会认为某些部分是“非规范化”的。
在这种情况下,我认为平衡是有序的。 如果把一个列放在一个表中是有道理的,那么把它放在表中,如果没有的话,那就不要。 你的同事方法肯定会帮助规范化数据库,但是如果你必须一起联合50个表来获得你所需要的信息,那么这可能不是很有用。
我想我的答案是,用你最好的判断。
有很多方面,但从应用效率的angular度来看,微粒表可以更有效率。 如果每次db执行一个操作时都有一堆列,那么它有可能发生locking,所以在锁的持续时间内,会有更多的数据不可用。 如果锁升级到页和表(希望不是表:)),你可以看到这是如何减慢系统。
嗯。
我认为它是一个洗,取决于你的特定devise模型。 当然,将拥有多个领域的实体排除在自己的表格之外,或者实体的构成可能会随着应用程序的需求变化而变化(例如,我总是把地址分解出来,因为它有很多字段,但是我如果你认为有可能需要处理外国的地址,可能会有不同的forms, 特别是这样做,电话号码也一样)。
也就是说,当你工作的时候,注意performance。 如果你把一个实体转换出来,需要你做大的昂贵的连接,也许把这个表转换回原来的devise决定会更好。
查询使用尽可能less的列有很大的好处。 但是桌子本身可以有很大的数量。 杰夫也对此说了一些话。
基本上,确保你在查询时不要求超出你的要求 – 查询的性能直接与你要求的列数有关。
我认为在做出决定之前,您必须查看您所存储的数据types。 有一个地址表是伟大的,但只有当多人共享相同的地址的可能性很高。 如果每个人都有不同的地址,将这些数据保存在不同的表中只会引入不必要的连接。
我不认为拥有城市桌的好处,除非他们自己的城市是你在申请中关心的实体。 或者如果你想限制你的用户可以使用的城市数量。
底线是这样的决定必须考虑应用程序本身考虑之前,你开始拍摄的效率。 IMO。
当你devise你的数据库时,你应该尽可能接近数据的意义,而不是你的应用程序需要!
一个好的数据库devise应该经过20年,没有任何变化。
一个客户可以有多个地址,这就是现实。 如果您认为您的应用程序仅限于第一个发行版的一个地址,那么应用程序的devise就不是数据的问题!
如果你想简化你的查询,最好有多个表而不是多列,并使用视图。
大多数情况下,数据库的性能问题与networking性能有关(单行结果的链查询,不需要的读取列等),而与查询的复杂性无关。
首先,规范你的表格。 这可以确保您避免冗余数据,为您扫描更less的数据行,从而改善您的查询。 然后,如果遇到正在join的规范化表导致查询花费很长时间来处理(昂贵的连接子句),那么将规范化到更合适的位置。
很高兴看到这么多鼓舞人心的,基于良好的答案。
我的答案是(不幸):这取决于。
两种情况:*如果你创build一个将被使用多年的数据模型,因此可能需要适应许多未来的变化:去更多的表,更less的行和非常严格的规范化。 *在其他情况下,您可以select更多的无表格行或更less的表格 – 更多的行。 特别是对于相对较新的人来说,这最后的方法可以更直观,更易于理解。
在面向对象的方法和其他选项之间进行select也是一样的。