在RavenDb中建模分层数据

时间:2013-12-22 15:04:15

标签: database nosql ravendb recursive-query

在RavenDb中,我必须存储分层数据,我需要递归地查询它。性能是这里最关注的问题。

我所拥有的与以下内容类似:

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Category Parent { get; set; }
}

在这种情况下,如果我将父类别存储在文档本身中,我将很难管理数据,因为我将在整个地方复制类别。

所以,为了方便起见,我可以将其存储如下:

public class Category
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Name { get; set; }
}

但在这种情况下,我不确定性能将如何,因为我将拥有数百万条记录,我需要从此参考创建类别树。

在性能是最关注的问题时,RavenDb中是否有关于如何建模此类数据的决定?

1 个答案:

答案 0 :(得分:4)

层次结构通常最好在一个定义层次结构的文档中建模。在您的情况下,将定义类别树,其中类别本身可以由独立文档表示(因此保持名称,描述等,并允许其他集合引用它们),或不。“

从代码建模,类别文档看起来像这样:

public class Category
{
    public string Id { get; set; }
    public string Name { get; set; }
    // other meta-data that you want to store per category, like image etc
}

层次结构树文档可以从类如下的类中序列化,其中该类可以使用方法使其中的节点易于访问:

public class CategoriesHierarchyTree
{
    public class Node
    {
       public string CategoryId { get; set; }
       public List<Node> Children { get; set; }
    }

    public List<Node> RootCategories { get; private set; }

    // various methods for looking up and updating tree structure
}

这种层次结构树的方法有几个重要的优点:

  1. 一个事务范围 - 当树发生更改时,树总是在一个事务中更改。您不能受到对树的多个并发更改的影响,因为您可以在编辑此文档时利用乐观并发。使用您提出的方法,无法保证随着时间的推移更难以保证层次树的完整性和正确性。如果您将层次结构视为树,那么让每个更改锁定整个树直到完成它实际上是很有意义的。层次结构树是一个实体。
  2. 缓存 - 即使使用积极的缓存,也可以快速有效地缓存整个层次结构,这将最大限度地减少使用层次结构上的查询访问服务器的时间。
  3. 所有操作都完全在内存中完成 - 因为它的一个文档,即对象,层次结构上的所有查询(其父项,子项列表等)完全在内存中,并且实际上成本几乎为零。使用具有Recurse()的索引来回答此类查询的成本是数量级的(网络成本和计算)。你提到性能是最大的担忧 - 所以这是一个胜利者。
  4. 每个类别有多个父项,没有非规范化 - 如果类别文档保存在层次结构树之外,如上所示,您可以有效地将类别放在多个父项下,而无需进行非规范化。所有类别数据都在一个地方,在树外的文档中,而树只包含对该类别的引用。
  5. 我强烈建议采用这种方法。这有点偏离关系心态,但即使树长大,它也是如此值得。