来自Relational世界的事情显然与Azure Table存储有很大不同。我遇到的第一个主要问题是如何正确存储多对多关系。
例如,我可能有一个跟踪他们拥有的用户和图书的系统。我在SO上找到了另一个帖子,建议在用户上有一个String属性,它基本上存储了用户拥有的Book ID列表。虽然我知道有时这是一种可接受的存储数据的方法,但问题是Azure只允许您在String中存储64KB的数据。这绝对限制了用户可能拥有的书籍数量。
另一种可能的解决方案是拥有重复数据。我可能有一个表存储系统中所有已知的书籍。但是当用户需要与Book相关联时,我将Book数据复制到另一个名为OwnedBooks的表中,该表基本上与Book表完全相同,只是它具有OwnedByUserID属性。
还有其他可能的解决方案吗?
除了这个问题,在使用Azure表存储时,是否有人对其他模式和实践有任何好的建议?
答案 0 :(得分:16)
有很多解决方案 - 当然都有缺点: - )
像在RDBMS中一样使用简单的映射表。每行包含一个Book键和一个User键。
然后,要查找用户的所有图书,您需要在映射表中选择Book键,然后为每个键选择Books表中的Book实体。您可以使用异步提取并行执行Book检索,但即便如此,此解决方案显然无法扩展。
使用上面的映射表,但也包括映射表中所需的所有Book数据。这是您已经在OwnedBooks表中提出的非规范化或“重复数据”解决方案。
这种方法的主要缺点是,如果你需要更新任何书籍数据,你可能会更新许多实体 - 而且当它们生活在书本身的单独表格中时,它将无法在单个事务/批处理中完成(我想你无论如何都要使用用户身份作为映射表中的分区键,这已经排除了该表中的单个批量更新)。
将Book键加入到User的单个属性中。同样,你已经建议了这个方法。
如果不是因为Azure目前不支持“包含”类型的查询 - 也就是说,你不能搜索子字符串,那么这实际上不会那么糟糕,所以如果你想找到它如果用户拥有特定的书,这是不可能的。有趣的是,Google App Engine在其存储系统中相当透明地支持它 - 并且也会为您索引列表。在任何情况下,您仍然需要使用此方法检索每本书的数据。
使用Azure表存储的“无架构”特性将关联的Book键存储为单个属性。例如,一个用户实体可能如下所示:
{
Name: "User1",
Book_4325: true,
Book_5123: true
}
虽然另一个可能看起来像这样:
{
Name: "User2",
Book_5346: true,
Book_8753: true,
Book_6135: true
}
然后,如果您确实想要找到拥有特定图书的所有用户,您可以选择该特定属性的真实位置(嗯,它只需要真正存在)。
明显的缺点是它有点脆,你需要在属性名称中使用键,而你无法使用StorageClient的标准方法 - 你必须自己滚动。此外,Azure仅支持实体上的255个属性。所有这一切,我认为它会扩展得很好 - 虽然我从未尝试过。
在所有这些选项中,我会说你要使用的那个,选项2,将是最好的,只是因为它目前支持Azure,你通常可以用更少的查询实现一切。
考虑到原子事务不在窗口,您只需要仔细检查用例以决定数据的更新方式和时间。我几乎可以保证你能够忍受“最终一致”的事情,并且只考虑到你的映射表可能并不总是100%最新的事实。
如果在主表的同时更新映射表中的数据变得太昂贵,您可以在队列上放置一条消息并获取辅助角色,以异步方式为您执行更新。
答案 1 :(得分:9)
你没有。这是Azure Table上的一个好的,完整的white paper(。dococ链接),其中包含有关最佳实践的部分。但是,您应该将Table用于非关系属性包或ORM类型设计。如果您想在云中使用关系,则应使用SQL Azure Database。
这是关于无架构存储与关系的另一个good article。它适用于different schema free cloud storage offering,但概念是相同的。