所以我和我的老板在如何最好地设计我们的数据库来为某些客户存储杂项数据方面存在分歧。
基本上,我们有一堆格式类似于此的表格(为简单起见,使用伪代码):
TABLE [dbo].[SalesData]
[CampaignID] int IDENTITY(1, 1) NOT NULL, (This is the PK)
[CustomerID] int NULL,
[Calls] float NULL,
[Responses] float NULL,
[Sales] float NULL,
[Revenue] money NULL,
[Cost] money NULL,
[WebSales] float NULL,
[Channel] nvarchar(20) NULL
当我们获得客户时,我们有时会被迫为每个客户添加某种自定义数据收集。对于此表,每个客户(我们有大约 20 个)都使用所有内容,WebSales 和 Channel 除外,它仅用于 1 个客户。另一个客户想要跟踪几条新数据,因此,我们要么需要添加更多列,要么将该数据分拆到相关表中并启动超类型-子类型系统。
我想做的也是分拆 WebSales 和 Channel,并以这种方式为每个客户添加一个表:
TABLE [dbo].[SalesData_Client1]
[CampaignID] int NOT NULL, (PK and FK to the SalesData table)
[WebSales] float NOT NULL DEFAULT 0,
[Channel] nvarchar(20) NOT NULL DEFAULT ''
ADD CONSTRAINT [CK__SalesData_Client1__CustomersCampaignID]
CHECK (dbo.CustomerOfCampaignID(CampaignID) = Client1)
然后我将从原始表中删除这些列,并使第二个客户端也成为这样的表。老板认为这意味着我们在获得客户时必须添加太多表,并希望添加更多列。他宁愿像这样更改 SalesData 表:
TABLE [dbo].[SalesData]
[CampaignID] int IDENTITY(1, 1) NOT NULL, (This is the PK)
[CustomerID] int NULL,
[Calls] float NULL,
[Responses] float NULL,
[Sales] float NULL,
[Revenue] money NULL,
[Cost] money NULL,
[Unknown] char(10) NULL,
[Misc1] float NULL,
[Misc2] nvarchar(20) NULL
[Misc3] int NULL,
[Misc4] int NULL
[Misc5] int NULL
“杂项”列可以用于任何用途,然后程序员可以“根据客户来解决”。我知道为什么你不应该这样做的原因,它违反了规范化,并且会随着我们添加列等而使性能越来越差。但他总是回来说“它更简单”并且不喜欢那样每个新客户都可能意味着另一个新表。他还指出,像 Websales 这样的新列最终可能会被不止一个客户使用,将它放在多个子类型表中,或者如果我们应该将它从多个子类型表移动到主表,将是一个巨大的痛苦曾经想那样做。
有没有比我想出的超类型/子类型解决方案更好的方法,可以让他和程序员的事情变得更容易?一个重要的注意事项是每个客户的数据基本上都在它自己的宇宙中,永远不会混合。我意识到这有点主观,答案将取决于我们认真期待的“杂项”专栏的数量。我想走子类型路线的原因是因为据我所知,下一个客户可能需要 5 个新的 bigint 列。
要真正灵活,您可以采用实体-属性-值路线,但这可能有点矫枉过正,许多人认为 EAV 是一种可怕的反模式。
如果您认为最终会在一个表中包含数十个特定于客户的列,我认为特定于客户的表可能是更好的选择。
在您的情况下,这可能不是正确的选择,但无论如何我都会把它扔掉。您可以有第二个表,其中包含
CampaignID
PK 以及所有各种客户特定的字段。它最终可能会非常宽,但您会保持类型安全和合理的名称,并且您的核心表会保持干净。因为您只会为具有任何自定义字段的客户存储一行,所以存储应该是合理的。您最终会得到稀疏列,但有一些工具可以使此类表保持快速和紧凑。您可以选择在自定义字段前加上客户姓名前缀,减少歧义但防止您为多个客户重复使用一个字段。
这类似于“垃圾维度”的数据仓库概念,它包含您不希望弄乱您的事实表但不认为拥有自己的维度表的所有杂项数据。
需要明确的是:我并不是真的在你的情况下推荐这个选项;恕我直言,任何需要定期进行 DDL 的解决方案都不是解决方案。我推荐 Frustrated 提供的 EAV 模式。