6

我有一个很常见的设计问题:我需要为 Google App Engine 中的记录实现历史日志(审计跟踪)。历史日志必须是结构化的,即我不能将所有更改加入到一些自由格式的文本中并存储在字符串字段中。

我已经考虑了历史模型的以下选项,并且在注意到选项 #1 中的性能问题后,我选择实施选项 #3。但是对于这个解决方案是否高效且可扩展仍有一些疑问。例如:随着选项#3 中动态属性数量的增加,是否存在性能显着下降的风险?

您是否对每个选项的优缺点有更深入的了解,或者可以建议适用于 Google App Engine DB 特征的其他审计跟踪设计模式?

  1. 使用经典 SQL 的“主从”关系
    • 优点
      • 对有 SQL 背景的数据库开发人员来说简单易懂
      • clean:直接定义历史记录及其属性
      • 搜索性能:轻松搜索历史(可以使用索引)
      • 故障排除:通过管理工具轻松访问 (_ah/admin)
    • 缺点
      • 通常不建议在 GAE DB 中以这种方式实现一对多关系
      • 读取性能:过多的记录读取操作以显示较长的审计跟踪,例如在大记录列表的详细信息窗格中。
  2. 在 BLOB 字段中存储历史记录(腌制的 Python 结构)
    • 优点
      • 实施简单且灵活
      • 读取性能:非常高效
    • 缺点
      • 查询性能:无法使用索引进行搜索
      • 故障排除:无法通过 admin db viewer (_ah/admin) 检查数据
      • unclean:对于 SQL 开发人员来说不太容易理解/接受(他们认为这很难看)
  3. 在 Expando 的动态属性中存储历史记录。例如,为每个字段fieldName创建history_fieldName_n字段(其中 n=<0..N> 是多个历史记录)
    • 优点:
      • 简单:易于实现和理解
      • 故障排除:可以通过管理界面读取所有历史属性
      • 读取性能:一次读取操作即可获取记录
    • 缺点:
      • 搜索性能:不能简单地搜索历史记录(它们有不同的名称)
      • 不太干净:属性的数量乍一看可能令人困惑
  4. 将历史记录存储在主记录中的一组列表字段中。例如。为每个fieldName创建一个fieldName_history列表字段
    • 优点:
      • clean:直接定义历史属性
      • 简单:SQL 开发人员易于理解
      • 读取性能:一次读取操作即可获取记录
    • 缺点:
      • 搜索性能:只能使用索引搜索任何时候都具有某些值的记录,而不能搜索在某个特定时间具有值组合的记录;
      • 故障排除:在 admin db viewer 中检查列表很困难
4

1 回答 1

3

如果我必须选择,我会选择选项 1。读取与其他选项一样(如果不是更多)性能。而所有其他选项仅在特定情况下(小或非常大的更改集)具有速度优势。它还将为您提供很大的灵活性(更轻松),例如在 x 天后清除历史记录或跨不同模型类型的查询历史记录。确保在同一事务中将历史实体创建为更改实体的子实体,以保证一致性。您最终可能会得到以下其中一项:

class HistoryEventFieldLevel(db.Model):
    # parent, you don't have to define this
    date = db.DateTime()
    model = db.StringProperty()
    property = db.StringProperty() # Name of changed property
    action = db.EnumProperty(['insert', 'update', 'delete'])
    old = db.PickleProperty() # Old value for field, empty on insert
    new = db.PickleProperty() # New value for field, empty on delete

class HistoryEventModelLevel(db.Model):
    # parent, you don't have to define this
    date = db.DateTime()
    model = db.StringProperty()
    action = db.EnumProperty(['insert', 'update', 'delete'])
    change = db.PickleProperty() # Dictionary with changed fields as keys and tuples (old value, new value) as values
于 2010-12-11T21:40:14.967 回答