You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CQRS实践疑问:是否应在写模型中扩展非规范化读字段?

问题背景

我正在开发一款基于事件溯源(Event Sourcing)和CQRS原则的交易追踪应用。每个Transaction关联一个Asset,相关模型代码如下:

class Asset(models.Model):
    code = models.CharField(...)
    current_price = models.DecimalField(...)
    sector = models.CharField(...)
    ...
    
    def get_roi(self, percentage: bool = False) -> Decimal:
        # 涉及多表关联的高成本计算
        return self.transactions.roi(incomes=self.incomes.sum(), percentage=percentage)["ROI"]


class Transaction(models.Model):
    asset = models.ForeignKey(to=Asset, on_delete=models.CASCADE, related_name="transactions")
    ...


class Income(models.Model):
    asset = models.ForeignKey(to=Asset, on_delete=models.CASCADE, related_name="incomes")
    ...

资产列表接口中有多个在规范化数据库中计算成本极高的字段,这些字段会在以下场景发生变化:

  • 创建或删除Transaction
  • 创建或删除Income
  • current_price变更

为了扩展性,我希望将这些高计算成本的字段与写模型分离,但读模型需要包含一些几乎不会变更的字段(如sector),用于生成按sector聚合ROI的报表。这意味着每次sector变更时也需要同步读模型,但这类字段的变更与Asset聚合领域的业务规则无关,这种同步方式让我觉得既奇怪又冗余。我考虑过直接在写模型中扩展这些非规范化字段,但这也存在问题。请问最优方案是什么?


最优方案建议

1. 读模型按需关联写模型的静态字段

让读模型只存储动态计算字段(如ROI、基于current_price的衍生值)和Asset的唯一标识(如asset_id)。当需要生成按sector聚合的报表时,在查询读模型的同时,通过asset_id关联写模型的sector字段。

  • 优势:完全避免sector变更时的同步操作,写模型无需关心读模型的静态字段需求,严格遵循CQRS读写分离的核心原则。
  • 注意事项:如果报表查询频率极高,关联查询可能带来性能损耗。可以在报表层添加缓存策略——比如按sector缓存聚合结果,仅当ROI或sector发生变更时更新缓存。

2. 将静态字段变更纳入事件流,用事件驱动同步读模型

给Asset领域新增一个AssetSectorUpdated事件,当sector字段变更时发布该事件,读模型的投影器监听此事件并更新自身的sector字段。

  • 优势:保持读模型的独立性,所有读模型的更新都通过事件驱动,符合Event Sourcing的架构一致性。虽然sector变更和业务规则无关,但事件驱动的方式让整个系统的数据流更清晰,不会破坏领域边界。
  • 注意事项:需要在写模型中添加sector变更的事件发布逻辑,属于少量额外开发,但逻辑可控。

3. 拆分读模型为动态聚合层与静态维度层

将读模型拆分为两个独立部分:

  • 动态聚合层:存储每个Asset的ROI、current_price等动态计算值,仅监听Transaction/Income/Price变更事件。
  • 静态维度层:存储Asset的sector、code等静态字段,仅在这些字段变更时更新。

报表查询时可以直接关联两层数据,或者构建物化视图定期合并两层数据,供报表快速查询。

  • 优势:彻底分离动态和静态字段的更新逻辑,避免不必要的同步操作,同时满足报表的聚合需求。
  • 注意事项:如果需要实时报表,需调整物化视图的刷新频率,或者采用实时关联查询的方式。

方案选择建议

如果报表的实时性要求不是极端严格,优先选择方案1,它最简洁且符合CQRS的设计初衷。如果报表查询性能要求极高,且sector变更频率极低,可以考虑方案2;若系统存在多种不同维度的报表需求,方案3的分层设计会更灵活。


内容的提问来源于stack exchange,提问作者Murilo Sitonio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 20:47:38