Python NDB中一对多关系的有效实现
我想听听你们对用Python NDB实现一对多关系的看法。(比如,一个人对应多个任务)
在我看来,有三种实现方式。
- 使用'parent'参数
- 使用'repeated'结构属性
- 使用'repeated'键属性
我通常根据下面的逻辑选择一种方式,但你觉得这样合理吗?如果你有更好的想法,请告诉我。
使用'parent'参数
- 这些实体之间需要进行事务操作
- 这些实体之间需要双向引用
- 明确表示'父子'关系
使用'repeated'结构属性
- 不需要单独使用'many'实体(总是和'one'实体一起使用)
- 'many'实体只被'one'实体引用
- 'repeated'的数量少于100
使用'repeated'键属性
- 需要单独使用'many'实体
- 'many'实体可以被其他实体引用
- 'repeated'的数量超过100
第二种方式会增加实体的大小,但我们可以节省数据存储操作的时间。(不过,我们需要使用投影查询来减少反序列化时的CPU时间)。所以,我尽量使用这种方式。
非常感谢你的意见。
2 个回答
大多数使用GAE(Google App Engine)的人都会发现一个问题,那就是它的数据存储方式并不鼓励按照传统的数据库设计原则来设计。这些原则在关系型数据库中被认为是好主意,但在这里却常常显得不太合适,甚至让人觉得不太直观。虽然关系型数据库的设计原则有它们的用处,但在这个环境下,它们并不适用。
我认为,数据存储的设计主要可以归结为两个问题:
我打算如何读取这些数据?怎样才能用最少的读取操作来获取数据?
这样存储数据会不会导致写入和索引操作数量激增?
如果你能尽量全面地回答这两个问题,并进行实际测试,我觉得你就做得不错了。你可以制定其他规则和具体情况,但这两个问题在大多数情况下都能派上用场。
你可能忽略了一个关键点:你是怎么读取数据的?
如果你是想在某个请求中显示某个人的所有任务,那选择第二种方式是合理的:你可以查询这个人,然后展示他的所有任务。
但是,如果你需要查询比如说某个时间到期的所有任务,那查询重复的结构属性就很糟糕。你会希望为每个任务单独创建实体。
还有一种第四种选择,就是在你的任务中使用一个指向人的“关键属性”。当你需要某个人的任务列表时,你可以发起一个查询。
如果你需要搜索单独的任务,那么你可能想选择第四种方式。你也可以把它和第三种方式结合使用。
另外,重复属性的数量和100没有关系。它完全取决于你的人和任务实体的大小,以及多少内容能放进1MB。这是有潜在风险的,因为如果你的任务实体可能很大,你可能会比预期更快地用完你的人实体的空间。