我目前正在为处理产品的小型微服务设计数据库模式。
该服务包含一个简单的 REST API,允许用户执行产品的基本管理,另一个 API 用于执行使用这些产品的操作。每个产品的最大消耗量受到明确定义的消耗品数量的限制。当达到此限制时,该产品将无法再食用。每个产品通常包含大约 1,000 - 1,000,000 个耗材,而单个操作一次可能需要 1 - 10 个耗材。
管理操作的频率很低,但消费操作的频率很高。
目前,该模式将所有产品信息放入一个表中。该表还包含必须在每个 INSERT、UPDATE 和 DELETE 操作上审计到基于快照的历史表中的信息。目前这是通过数据库触发器完成的,它知道如何将行与其他审计信息一起添加到历史表中。每个消耗品使用还会在消耗品表中添加一个新行,其中包含一些与消耗方式相关的附加信息。
这是一个关于这些表当前如何组织的简化示例。
------------------------
| product |
------------------------
| + id |
| + name |
| + is_enabled |
| + consumable_limit |
| + consumable_counter |
| ...10 omitted fields |
------------------------
------------------------
| product_history |
------------------------
| + id |
| + product_id |
| + time |
| + user_id |
| + history_type |
| + name |
| + is_enabled |
| + consumable_limit |
| + consumable_counter |
| ...10 omitted fields |
------------------------
------------------------
| operations |
------------------------
| + id |
| + product_id |
| + consumable_idx |
| ...10 omitted fields |
------------------------
在上图中,我省略了一些字段以使事情更简单。让我想知道的是,产品表中的 consumable_counter 会随着消费操作快速更新,这可能会进一步淹没 product_history 表。每次更新 consumable_counter 时,将 consumable 计数器移动到另一个表中不会触发产品表行的完整快照会更好吗?不知何故,我觉得它可能是理想的,因为 consumable_counter 是产品表中唯一以高速率更新的列。每个计数器增量的完整快照不知何故感觉有点矫枉过正。
编辑
consumable_counter充当相应产品已使用次数的计数器。当达到consumable_limit时,产品将无法再被消耗。
编辑
每次消费产品时,都会在操作表中添加一个新条目。此表中的条目还充当包含将在操作执行流程期间管理的状态的业务逻辑事务。
我认为您的评估正朝着正确的方向发展。您似乎确实捕获了太多信息。根据您的描述,我认为您描述的是消费事件而不是产品历史。
我的建议是考虑将 PRODUCT_HISTORY 表中的消费属性拆分到一个新表中。在不知道省略的列的情况下,我无法提供建议。以下是一些想法:
如果“名称”列是产品的名称,则不会随着消费事件而改变,并且应该保留在产品历史记录中。
消费限制可能需要在产品历史和消费事件表中。您可能需要知道消费发生时的限额是多少,并且限额可能会随时间而变化,因此该事实应记录在产品历史表中。
可能需要消费事件和操作表之间的关系
操作表中的一行是描述单个操作的集合(可能还有一个操作表)还是单个操作?这是弄清楚与消费事件的关系的一个重要细节。如果它是单数,我建议您重命名该表。
简短的回答:
是的,如果一个属性的更新频率很高,而另一个属性的更新频率很低,那么将审计表分成两个主题区域是完全可以接受的。但这更多地与降低写入开销有关,并可能使某些属性的更改更容易找到,而不是设计的好坏。
长答案:
银行和其他机构不存储余额/数量的静态金额是有原因的。即:
请参阅 SO 的这两个答案,它们提供的洞察力和指导比我能提供的更多:
https://stackoverflow.com/a/29713230/13942986
https://stackoverflow.com/a/59465148/13942986
额外的观察
Id
你product_history
和表上的operations
是行指针,而不是键,完全没有必要。两种情况下的主键都应该是(product_id, update_datetime)
or(product_id, transaction_datetime)
。Id
为product
。product_id
operation
,不是operations
。