针对不同的排序和过滤条件应该创建哪些MongoDB索引来提高性能?

Max*_*kiy 5 sorting query-optimization mongodb mongodb-indexes

我有大约 100,000,000 条记录的 MongoDB 集合。

\n\n

在网站上,用户使用“细化搜索”功能搜索这些记录,他们可以按多个条件进行过滤:

\n\n
    \n
  • 按国家、州、地区;
  • \n
  • 按价格范围;
  • \n
  • 按行业分类;
  • \n
\n\n

此外,他们还可以查看排序的搜索结果:

\n\n
    \n
  • 按标题(升序/降序),
  • \n
  • 按价格(升/降),
  • \n
  • 通过 bestMatch 字段。
  • \n
\n\n

我需要创建索引以避免对上述任何组合进行全面扫描(因为用户使用大多数组合)。遵循相等排序范围规则,我必须创建很多索引:

\n\n

所有过滤器组合 \xc3\x97 所有排序 \xc3\x97 所有范围过滤器,如下所示:

\n\n
country_title\nstate_title\nregion_title\ntitle_price\nindustry_title\ncountry_title_price\ncountry_industry_title\nstate_industry_title\n...\ncountry_price\nstate_price\nregion_price\n...\ncountry_bestMatch\nstate_bestMatch\nregion_bestMatch\n...\n
Run Code Online (Sandbox Code Playgroud)\n\n

事实上,我有更多的标准(包括相等和范围),以及更多的排序。例如,我有多个价格字段,用户可以按任何价格排序,因此我必须为每个价格字段创建所有过滤索引,以防用户按该价格排序。

\n\n

我们使用 MongoDB 4.0.9,目前只有一台服务器。

\n\n

在我进行排序之前,这会更容易,至少我可以有一个复合索引,例如country_state_region当搜索某个地区时,并且始终在查询中包含国家/地区和州。但是在最后有排序字段,我不能再这样做了 - 即使对于位置(国家/州/地区),我也必须使用所有排序组合创建所有不同的索引。

\n\n

另外,并不是所有的产品都有价格,所以我不能只按price字段排序。相反,我必须创建两个索引:{hasPrice: -1, price: 1}{hasPrice: -1, price: -1}(此处,hasPrice 为 -1,无论价格排序方向如何,始终首先包含 hasPrice=true 的记录)。

\n\n

目前,我使用 NodeJS 代码生成类似于以下内容的索引(这是简化的示例):

\n\n
country_title\nstate_title\nregion_title\ntitle_price\nindustry_title\ncountry_title_price\ncountry_industry_title\nstate_industry_title\n...\ncountry_price\nstate_price\nregion_price\n...\ncountry_bestMatch\nstate_bestMatch\nregion_bestMatch\n...\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,上面的代码生成了 90 多个索引。而在我真正的任务中,这个数字甚至更多。

\n\n

是否可以以某种方式减少索引数量而不降低查询性能?

\n\n

谢谢!

\n

Raj*_*oel 5

首先,在MongoDB中(参考: https: //docs.mongodb.com/manual/reference/limits/),单个集合最多可以有64个索引。另外,除非没有写入或写入次数很少,否则永远不应该创建 64 个索引。

是否可以以某种方式减少索引数量而不降低查询性能? 在不牺牲功能和查询性能的情况下,您不能这样做。

您可以做的几件事:(假设您使用分页来显示结果)

  1. 在每列上创建一个单独的(非复合)索引,并让 MongoDB 执行计划器根据其拥有的元信息(基数、数字等)选择索引。当然,性能也会受到影响。

  2. 根据您的判断和一些分析,仅为最常用的组合创建复合索引。

  3. 最重要的是- 在创建复合索引时,您可以放弃对列进行排序。假设您正在根据行业进行过滤并根据价格进行排序。如果你有一个复合指数(行业、价格),那么一切都会正常进行。但是,如果您仅对行业有索引(假设分页结果),那么前几页的查询将非常快,但当您进入下一页时,查询的性能会不断下降。一般来说,用户在浏览 5-6 个页面后就不会再进行导航。另外,您必须记住,对于较大的跳过值,查询将开始失败,因为排序的 32mb 内存限制。这可以通过启用allowDiskUse 的聚合(而不是查询)来克服。

  4. 检查键集分页(也称为搜索方法)是否可以在您的用例中使用。