RavenDB数据模型有效的可扩展性设计选择

时间:2013-02-13 08:58:15

标签: database-design mapreduce scalability ravendb

我正在正在开发的项目中使用RavenDB,因此还没有用户。我的背景一直是关系数据库,直到这个项目,但我更喜欢NoSQL方法。但是,我还没有任何工作或管理在NoSQL数据库上构建的网站的经验,这个网站流量很大。我开始理解Map / Reduce索引,并在我的解决方案中包含了一些,但我想知道:

关于何时创建Map / Reduce索引以及何时不关注索引,我是否应该遵循任何设计经验法则?

我知道它非常依赖于我在系统中的业务对象以及它们如何相互交互。我想我只是在努力查看我可能会使用索引进行哪些查询的大图,我可以直接查询对象。

以下是我的业务领域的部分内容以及我已经创建索引的位置的快速概述:

我的系统主要由品牌和消费者组成。每个人都有很多社交媒体账户。当用户通过其社交媒体帐户登录时,我有索引BrandsBySocialAccountConsumersBySocialAccount,这些索引会将这些收藏展平并将其与品牌或消费者的UserId相关联。一旦我拥有UserId,我就可以检索相关的品牌或消费者记录,然后离开。

品牌可以制作多个广告系列。我在这里有另一个索引,CampaignsByBrand。还需要跟踪消费者与广告系列的互动方式,因此广告系列可以针对他们可以针对广告系列执行的不同互动设置许多跟踪条目。他们可以在外部跟踪指向活动页面的链接,也可以从网站内部发现一个链接。正如我解释的那样,似乎很明显我需要索引。我有一个包含交互的每个交互索引(ClickLinkTrackingEntriesByCampaignViewDetailsTrackingEntriesByCampaign)或一个索引(TrackingEntriesByCampaign)。多个索引是否过度杀伤?它可能是。目前有4种类型的交互,后面可能会介绍其他类型的交互。当我有一些记录时,这些查询非常快。但是,当有数十万甚至数百万条记录时,它们仍然会尽可能快吗?

查看整体设计,似乎对于每个具有可能需要由该集合上的属性查询的集合属性的对象,我应该创建Map / Reduce索引。这是一个很好的经验法则吗?还有其他人 - “如果你有这些类型的对象交互,你应该考虑创建这些类型的索引”

1 个答案:

答案 0 :(得分:2)

首先,如果您尚未查看static indexes上的文档,请务必查看。

您需要明确的要点是:

  1. 直接从文档存储中检索文档需要索引,应尽可能使用。这可以使用以下任何一种方法完成:
    • session.Load()
    • session.Advanced.LoadStartingWith()
    • documentStore.DatabaseCommands.Get()

  2. 每次使用session.Query()session.Advanced.LuceneQuery()进行查询时,您总是使用索引。如果未指定静态索引索引,则会为您创建dynamic index。在许多情况下,创建动态索引所涉及的延迟不太理想 - 因此用静态索引替换动态索引通常是个好主意。

  3. 您拥有的索引越多,服务器必须执行的工作就越多,您将消耗的存储空间也越多。因此,您可能希望尽可能合并索引。通常,相同的索引可用于多种目的。你应该仔细制作你的指数 - 不要让它们太窄而不能用,并且不要使它们变得广泛和昂贵。

    假设我有一个对象需要按字段A进行查询,有时候按字段B进行查询。当然,我可以创建两个不同的索引,但这会浪费。使用映射AB字段的单个索引会更有效。现在,两个不同的查询可以由同一索引提供。我建议您尽可能合并索引。

    一个典型的错误的示例是映射文档中的每个字段并为所有字段打开字段存储,只是因为您认为您可能希望在某个时刻从索引中投影它们。在大多数情况下,您不需要走这么远。有几个地方这是合适的,但你会非常谨慎地做。

  4. 所有索引都有 Map ,但我们不会将它们称为“map / reduce”索引,直到它们还有 Reduce 部分。您将创建的大多数索引是map / reduce索引。

    Map / Reduce索引几乎总是保留用于某种类型的聚合计算。例如,您的域中可能有SocialAccountsCountByBrand的m / r索引,或者您可能在销售域中有TopCustomersByTotalSalesPerMonth之类的更复杂的索引。

  5. 我不同意你的评估,如果一个对象有一个集合属性,它需要一个索引超过该集合。在许多情况下,您在域中的其他位置会有类似的数据,可以用于相同的目的。当然,细节取决于你想做什么。但总的来说,如果您发现正在创建大量这些索引 - 通过将数据重构到自己的文档中可能会更好。

    例如,如果我有类似以下的类怎么办?

    (故意不好的例子 - 不要真的这样做)

    public class Customer
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public List<Order> Orders { get; set; }
    }
    

    显然,如果每个订单都嵌入在Customer对象中,我会经常查询该集合。将每个Order放入自己的文档中,通过CustomerId引用返回给客户,我会更好地服务>

  6. 最后,尽量避免根据您想要的结果形状来考虑索引。相反,请根据您要查询的内容来考虑它们。换句话说,您希望在查询中的WhereOrderBySearch条款中指定哪些字段?

    当然,有live projectionsTransformResults等技术 - 但同样应该谨慎使用这些技术。现在我们有更强大的功能,如indexing related documents,人们可以反对几乎所有的转型需求。一些次要的索引预测可能很有用,但通常您可以在自己的代码中操作结果并让乌鸦远离它。仅在实际需要结果中索引的数据时才使用投影。如果您需要的所有数据都在文档中,则无需投影。

    我提出这一点,因为我看到很多人根据用户界面中的ViewModel设计索引。这很糟糕,因为它要求为UI问题制定索引。人们应该考虑结果本身的形状。如果它具有回答查询的所有信息,那么它可以以多种方式使用 - 包括但不限于UI。

  7. 我希望这能回答你的问题。如果您有其他人,请在评论中回复。感谢。