这应该在数据库中表示为1个表还是3个表?我和我的朋友对此有不同的看法,所以我希望看到对此的一般看法。 (也许它应该是对任何一种解决方案的投票?)
Create Table Order
// Basic fields of the table
- ID (Primary key)
- CustomerID (integer, with a FK)
- Quantity
- ProductID (integer, with a FK)
// Then depending on user selection, either these fields need to be specified
// (could be factored out to a separate table):
{
- InternalAccountID (integer, with a FK)
- InternalCompanyID (integer, with a FK)
}
// Or these (could be factored out to a separate table):
{
- ExternalAccountNumber (free text string)
- ExternalCompanyName (free text string)
- ExtraInformation (free text string)
}
请求优点和缺点以及个人意见。 :)
编辑:我尝试使用与实际使用不同的实体来简化示例,因此任何改变模型的建议都不会对我有所帮助。即请关注技术方面而不是领域模型。
答案 0 :(得分:3)
我的意见是,如果
// Then depending on user selection, either these fields need to be specified
// (could be factored out to a separate table):
{
- InternalAccountID (integer, with a FK)
- InternalCompanyID (integer, with a FK)
}
// Or these (could be factored out to a separate table):
{
- ExternalAccountNumber (free text string)
- ExternalCompanyName (free text string)
- ExtraInformation (free text string)
}
始终是1:1的订单(即,您不能有3个帐户ID),然后将其保留为一个表。要处理您的null问题,您可以添加一个名为InternalCustomer(boolean)或CustomerType(varChar)的列,您可以使用它来定义内部或外部客户,以了解您应该查看哪两个字段集中的哪一个特定客户。
由于我们不知道完整使用此数据或整个数据库的模式,因此对此的任何响应都不能完全合格。
答案 1 :(得分:3)
答案 2 :(得分:0)
如果您想避免数据重复,您应该使用2或3表解决方案。例如,如果Order表中有External
列,则值可能会多次存在。如果数据如下所示:
ID ExternalCompanyName
1 ACME
2 ACME
3 My Company
4 ACME
现在,如果ACME将名称更改为ACME,Inc。,则必须更新许多行。如果表是规范化的,外部公司在一个单独的表中,您将更新一行。请注意,可能存在将帐号放在其自己的表中的参数,但我们将其保留为极端规范化。
订单与公司/帐户之间似乎不是一对一关系,除非每个公司/帐户只能有一个订单。这听起来更像是一对多的关系。
现在,如果在单表环境中更新ExternalCompanyName时出错,并且只有部分行得到更新,会发生什么。你有一些使用ACME的行和一些使用ACME,Inc的行。你最终会出现数据不佳的情况。
此外,如果这真的是一对多的关系,那么你真的不会节省空间。您正在按顺序复制数据,而不是将其存储在另一个表中。
答案 3 :(得分:0)
随着音量的增加两个表的选择可能比一个快得多。有时,这种重构(分区)是在成熟的数据库上完成的,以提高性能。
想象一下,将此用于多表连接,其中某些条件在此表中,但其他条目位于不同的表中。
select from order join customer using (customer_id)
where
order.order_date between ? and ?
and customer.name = ?
最终可能会从磁盘中获取日期的所有order
行,然后将其中的许多行丢弃,因为它们与连接不匹配。从磁盘获取的速度很快,可能会破坏您的RAM缓存。
select from order join order_detail using (order_id) join customer using (customer_id)
where
order.order_date between ? and ?
and customer.name = ?
在这种情况下,当它从磁盘加载所有order
行时,它不会像以前那样受到伤害,因为表格更窄更小。它不需要加载与过滤无关的所有冗长字段。最后,加入customer
后,它只会获取符合所有条件的order_detail
行。
如果您希望这个很大,则应考虑拆分表,以便对搜索最关键的字段位于一个表中,而“data”字段位于其他一对一表中。 / p>
底线是:普通形式和域名是一回事,但性能通常需要权衡。您可以隐藏其中一些(用视图覆盖拆分),但不是全部(为了更快的选择而重复/聚合字段)。
答案 4 :(得分:0)
我绝对不使用3表解决方案。通过将这些数据分成3个表,您实际上不能让任何查询返回完整的订单头而不加入外键,并且每个新订单的插入都会更新多个表和索引,这是并发问题。我建议使用2个表,一个用于InternalOrders,一个用于ExternalOrders。对于需要对来自两组订单的数据进行综合查询的情况,请定义一个视图,该视图是两个表的并集。
我我惊讶地看到产品ID和数量是订单标题的一部分。我见过的每个订单跟踪数据库都将订单项作为单独的表分开,使用订单ID作为外键,这样一个订单可以包含多个产品(或者具有不同数量,交货时间等的相同产品)。 )。
答案 5 :(得分:0)
我不是纯粹主义者,所以当它有意义时,3nf是好的......但你不必理所当然地认为它总会如此。
从务实的角度来看,你的目标是什么?您的利弊列表是一个良好的开端。我会在列表中添加一些想法 - 正如您认为合适的那样。
1)数据库中的任何其他表是否需要与此数据相关(例如,加入)?这就是RDB的重点。
2)您的数据库会增长吗?即使一张表现在有意义,它总是有意义的吗?你会后悔的,如果你发现自己想要添加更多的表,并且你的非规范化表强迫你“解决”它,处理返回的额外行,执行时间较慢等等。
3)当您的客户获得新的外部帐户或您有什么时,会发生什么。你会创造一个全新的记录吗?您如何回答诸如“什么是客户某某的账号?”等问题。
...
我认为一般来说,我选择可扩展,在这种情况下可能意味着3nf。 1表在一个非常狭窄的范围内更容易处理,但如果有任何变化,你将处理“如何将此表拆分为正确相关的3nf表,而不会弄乱所有已创建的依赖关系它?”。那个没有乐趣。
答案 6 :(得分:0)
在他可以订购之前是否与客户相关联的帐户信息(即您有另一张表,您可以在其中跟踪客户ID可以使用的帐户ID)?您是否可以将所有帐户抽象为一个合理统一的模式(一个可以有一些空值),因为您有一个通用的AccountId(代理键),然后Account表中有3个varchar字段,另一个跟踪帐户的类型(使用过)用于计费等)?
如果您可以这样做,那么您的订单只跟踪一个AccountID,因为订单(作为实体)实际上并不关心使用哪种付款方式 - 它只关心它是该用户的合法/现有/批准的AccountId。其他一切都是别人的业务,可以这么说(计费或检查资金等),而且无论如何,它的处理都需要更多数据。
这可以保持您的订单清洁无效,并且也可以帮助分离关注点。
从概念上讲,您的订单实际上是所谓的事实表 - 仅包含数字和FK-s,项目大小较小但数量较多。
所以:
Table Order (
- OrderId
- Quantity
- ProductId
- DiscountId -- sonner or latter :-)
- AccountId
- PaymentStatus -- probaly FK as well or predefined constant
)
Table Account (
- AccountId
- BillingInfo -- akka ext acct number as text
- PrincialName -- akka ext company name, some equivalent for internal acct-s
- AdditionalData
)