1

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

关于何时创建 Map/Reduce 索引以及何时不创建索引,我应该遵循任何设计规则吗?

我知道这非常依赖于我系统中的业务对象以及它们之间的交互方式。我想我只是在努力了解我可能进行的哪些查询应该使用索引,以及我可以简单地直接查询对象。

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

我的系统主要由品牌和消费者组成。每个人都有许多社交媒体帐户。当用户通过他们的社交媒体帐户登录时,我有索引BrandsBySocialAccountConsumersBySocialAccount,它们将这些集合展平并将它们与UserId品牌或消费者相关联。一旦我有了,UserId我就可以检索相关的品牌或消费者记录,然后我就走了。

一个品牌可以创建许多活动。我这里有另一个索引,CampaignsByBrand. 还需要跟踪消费者与活动的交互方式,因此活动可以有许多跟踪条目,用于他们可以与活动执行的不同交互。例如,他们可以从外部跟踪到活动页面的链接,也可以从网站本身中发现一个。正如我解释的那样,我在这里需要索引似乎很清楚。每次交互都有一个索引 ( ClickLinkTrackingEntriesByCampaignand ViewDetailsTrackingEntriesByCampaign) 或一个索引 (TrackingEntriesByCampaign) 包含交互。多个索引在这里过分吗?可能是。目前有 4 种交互类型,以后可能还会介绍其他类型。当我有几条记录时,这些查询非常快。但是当有数十万甚至数百万条记录时,它们仍然会尽可能快吗?

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

4

1 回答 1

2

首先,如果您还没有查看有关静态索引的文档,请务必查看。

您需要清楚的要点是:

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

  2. 任何时候使用session.Query()or查询时session.Advanced.LuceneQuery(),您总是在使用索引。如果您不指定静态索引索引,则会为您创建一个动态索引。在许多情况下,创建动态索引所涉及的延迟并不理想——因此用静态索引替换动态索引通常是个好主意。

  3. 您拥有的索引越多,服务器必须完成的工作就越多,您将消耗的存储空间也就越多。因此,您将希望尽可能合并索引。很多时候,同一个索引可以用于多种用途。你应该仔细地设计你的索引——不要把它们弄得太窄而无用,也不要把它们弄得太宽和昂贵。

    假设我有一个对象,有时需要按字段查询,A有时也需要按字段查询B。当然,我可以创建两个不同的索引,但这会很浪费。A拥有一个同时映射和B字段的索引会更有效率。现在两个不同的查询可以由同一个索引提供服务。我敦促您尽可能合并索引。

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

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

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

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

    例如,如果我有一个像下面这样的类:

    (故意的坏例子——不要真的这样做)

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

    显然,如果每个订单都嵌入到Customer对象中,我会非常频繁地查询该集合。将每一个都放入自己的文档中,通过引用回馈给客户,我会得到更好的服务。OrderCustomerId

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

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

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

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

于 2013-02-13T16:44:39.347 回答