nig*_*der 18 mysql sql database sql-server database-design
我有一个客户表,其中包含有关我们客户的信息(ID,登录名,姓名,联系信息,不同选项,TS列等,约15列,〜几百个客户).
现在我们需要向我们最大的客户发送每日更新(<10%的客户).我需要存储发送给客户的最新更新的时间戳,所以下次我只发送新的更新(我的意思是在TS大于存储的TS的订单行中更新).
如果我将一个新列"LastUpdatesSentTS"添加到customers表中,那么,据我所知,它将符合规范化规则(如果没有,请提供证明它将破坏规范化的链接).
但是,正如我也知道,从物理数据库设计的角度,最好是创建2列[客户,LastUpdatesSentTS]新表,因为客户只有不到10%的有TS存储的信息.我的意思是,如果我将列添加到customers表 - 大多数客户在该列中将为null.另外,如果我创建一个单独的新表,也许这将是更好地从客户表中删除布尔列"SendUpdates"(因为我将能够了解哪些客户需要更新,通过连接客户表,新表发送).此外,在这种情况下,我担心在几年内我会有一堆非常小的表,当它全部可以在客户表中(没有按照我的理解打破规范化).
简单来说,我看到了两种可能的表格设计:
1)
Table customers:
[CustomerID, Name, ..., SendUpdates, LastUpdatesSentTS]
Run Code Online (Sandbox Code Playgroud)
2)
Table customers:
[CustomerID, Name, ...]
Table customer_updates_sending:
[CustomerID, LastUpdatesSentTS]
Run Code Online (Sandbox Code Playgroud)
你怎么看?
Cra*_*gTP 16
我建议您应该将其作为第二个单独的表格.
原因在于,正如您在问题中所建议的那样,只有大约10%的客户需要这些"更新",因此"客户"表中大约90%的记录将包含一个始终包含NULL值的字段,如果您将其作为同一客户表上的附加字段.将其实现为第二个表可以避免此问题.
这不是一个大问题,因为您的客户表非常小,但在设计类似这样的东西时,我会考虑的更重要的问题是面向未来.
基本上我可能会问自己:
"在未来的任何时候,我是否需要了解客户的 更新历史,而不仅仅是最后一个?"
根据它的应用(听起来像是你所说的业务驱动程序),可能需要检查客户更新历史.想想管理信息,报告,年度总结等)
在我写过的几乎所有业务应用程序中,为了这些确切的目的,我必须保留至少几年的所有内容(然后通常将其存档到数据仓库或单独的数据库).
即使您对客户的更新历史不感兴趣,我个人更喜欢2表方法,因为它肯定允许保留历史记录,并提供更好的设计方法(因为只有来自customers表的一些记录需要记录第二个"更新"表).但是,请参阅下面的编辑以获取更多信息.如果我知道这些数据永远不需要历史记录,那么我将在现有客户表上实现一个额外的字段.
另外,不要担心数据库中有一堆"非常小的表".通常有很好的理由使用它们,并且是对象 - 关系阻抗不匹配的一部分,并且通常在应用程序代码中通过更"内聚"的面向对象设计来克服.
编辑:
(回应对我的回答的评论).
Aaron Bertrand提出了一个非常有效的观点,如果你有许多额外的数据实例就像这样,并且每次通过主键链接时你不断使用一个单独的表,你会得到一个非常小的过多用于保存有关您的一个客户的数据的表格.在查询数据库以便为一个客户提取一组完整的数据时,这可能变得特别麻烦,并且JOINS在许多表上过多且效率低下而负担过重.
根据"附加"数据的性质,人们必须就如何实施这些数据做出务实的决定.Aaron建议,在"LastUpdate"日期字段的情况下,NULL在90%的客户表中拥有大量的东西并不是坏事,我在这里同意他,从这个角度来看NULL,这个这不是一件坏事.我自己建议使用2表方法并不是基于删除它的愿望NULL(尽管它确实实现了这一点),而是确保可以保持"LastUpdate"日期的历史.
当然,如果完全不需要保留历史记录(并且记住明天可能需要明天不需要的那些),那么将"LastUpdate"日期作为同一"客户"表上的附加字段实现将没有问题.实际上,如果单个客户和单个"最后更新"日期之间只存在直接的一对一关系,那么将其拆分为2个表将是错误的.在这种情况下,我将它作为customers表上的附加字段实现,因为它现在是该客户的标量值属性.
当然,您现在可以始终在客户表上实现一个单独的字段,如果它成为一个要求(让我们说一年下线)现在保留"最后更新"日期的历史记录,您始终可以重构您的数据库将其拆分为第二个表,但请记住,您只是从那一点收集历史数据,因为您将没有上一年的最后更新日期的记录.
如果你这样做(或会)要求的"最后更新"日期的历史记录(即一个一对多的客户记录和"最后更新"日期记录之间的关系),然后用第二个表的方法,通过主键联是唯一的选择.
"如果有疑问,做最简单的事情可能会奏效" - 沃德坎宁安
有时我会说"添加第二张桌子",但在这种情况下,我觉得这不合理.据我了解,没有要求维护此属性的值历史记录.桌很小.而且,最终,您所获得的是客户的属性.当然,并非所有这些都会被填充,但对我来说这是次要考虑因素.在大多数情况下,许多字段都具有NULL值,但这并不意味着您必须创建第二个表来保存它们.保持尽可能简单(并且尽可能简化),但不要简单(或者正常:-).所以,如果是我,我会将这些字段添加到CUSTOMERS表中.因人而异.
分享和享受.
我会选择选项 2。
我不喜欢有像SendUpdates. IMO,最好将其存储在不同表中的行中。
SELECT * FROM customer_updates_sending;
Run Code Online (Sandbox Code Playgroud)
比更简单、更快
SELECT * FROM customers WHERE SendUpdates = 1;
Run Code Online (Sandbox Code Playgroud)
对评论的进一步想法:
是的,我主张为附加属性创建附加表,前提是每个属性都与不同且不相关的任务或操作相关联。添加与单独任务无关的属性应添加到第一个表中(例如买家的中间名)。
在本例中,属性(时间戳)与任务(联系客户)相关联。与联系客户相关的所有信息都应包含在该表中。(例如联系地址)。
我不确定你的意思是“你必须更改每个表中的源查询”。表是一组信息。您不会将查询保存在表中。
您不会有 15 个联接的大型查询,因为您只需要与您当前正在执行的任何任务有关的联接。只要您不寄出这封信,您就不需要该信息。当您确实需要该信息时,只需加入 1 次即可。