假设 A 和 B 在概念上是不同的实体,它们具有一些相似的属性,当然还有它们自己的特定属性。在数据库设计中,我应该将这两个实体放在一个大聚合表中还是两个分别设计的表中。
\n\n例如,我有两种付款方式;在线支付和手动支付的定义如下,
\n\nTABLE [OnlinePayments]\n( \n    [ID] [uniqueidentifier], \n    [UserID] [uniqueidentifier], \n    [TrackingCode] [nvarchar](32), \n    [ReferingCode] [nvarchar](32),\n    [BankingAccID] [uniqueidentifier],\n    [Status] [int],\n    [Amount] [money],\n    [Comments] [nvarchar](768),\n    [CreatedAt] [datetime],\n    [ShopingCartID] [uniqueidentifier],\n)\n和
\n\nTABLE [ManualPayments]\n(\n [ID] [uniqueidentifier],\n [UserID] [uniqueidentifier],\n [BankingAccID] [uniqueidentifier],\n [BankingOrgID] [uniqueidentifier],\n [BranchName] [nvarchar](64),\n [BranchCode] [nvarchar](16),\n [Amount] [money],\n [SlipNumber] [nvarchar](64),\n [SlipImage] [image],\n [PaidAt] [datetime],\n [Comments] [nvarchar](768),\n [CreatedAt] [datetime],\n [IsApproved] [bit],\n [ApprovedByID] [uniqueidentifier],\n)\n我的一位朋友告诉我,为此类相似的实体创建两个不同的表并不是一种良好的设计方法,为了提高性能和易于数据操作,应将它们放在一个表中。
\n\nI\xe2\x80\x99m 现在想知道该怎么办?在这种情况下,最佳做法是什么?
\n你的问题以一个有趣的词开始:“概念上”。从概念上 - 逻辑上 - 所有付款基本上都是相同的。大多数时候,您的应用程序可能只对付款感兴趣- 客户付款了吗?付款已处理吗?我们需要退款吗?
因此,从概念上讲,您的应用程序可能需要一个 PAYMENTS 表。但是,您有两种不同的付款类型,并且将来可能会有其他类型(直接借记、定期订单)。您可以通过三种方式表示这些子类型:
根据经验,我发现单个表对于编码来说绝对是一场噩梦。当我们只有两个子类型时,我们可能会侥幸逃脱,但是我们添加的子类型越多,逻辑就会变得越粗糙。这也意味着我们无法引用外键中的子类型。
在我看来,“无公共表”解决方案比单个表更好。它的主要缺点是它使得与通用实体一起工作变得更加困难。我们无法针对付款强制执行外键。拥有一个支持跨表共享 UID(例如 Oracle 的序列)并支持 UNION ALL 运算符的数据库也很有帮助。
超类型加子类型的方案绝对是最好的方案。它使我们能够更轻松地处理通用付款和特定类型的付款。我们得到了一个直观的数据模型,我们能够以适当的粒度强制执行外键,我们得到了适合我们应用程序工作方式的东西。
但是,您使用的 LINQ-to-SQL 当前不支持超类型/子类型实现。由 ORM 工具的局限性驱动的数据模型让我非常烦恼。共享数据库的其他应用程序必须支付不合标准模型的成本,即使它们不使用相关的 ORM 工具(多个客户端访问一个数据库是很常见的)。
反正 ....
保持当前的设计。它更简单、更干净。至于性能,虽然在某些情况下单个表速度更快,但在其他情况下单独的表性能会更好。此外,当您确实需要处理一般付款时,SQL Server 支持UNION ALL。