MongoDB Find 性能:单个复合索引 VS 两个单字段索引
Posted
技术标签:
【中文标题】MongoDB Find 性能:单个复合索引 VS 两个单字段索引【英文标题】:MongoDB Find performance: single compound index VS two single field indexes 【发布时间】:2018-06-02 06:43:54 【问题描述】:我正在寻找有关在 MongoDb 3.4 中使用哪种索引策略的建议。
假设我们有一个 people 文档集合,其形状如下:
_id: 10,
name: "Bob",
age: 32,
profession: "Hacker"
让我们假设一个用于查询集合的 web api 被公开,唯一可能的过滤器是 name 或 age。
对 api 的示例调用将类似于:http://myAwesomeWebSite/people?name="Bob"&age=25
这样的调用将在以下查询中翻译:db.people.find(name: "Bob", age: 25)
。
为了更好地阐明我们的场景,请考虑:
字段 name 已经在我们的文档中,并且我们已经在该字段上建立了索引 由于我们的应用程序的一些新功能,我们将添加新字段 age 数据库只能通过上面提到的web api访问,最重要的要求是暴露一个超快速的web api 对 web api 的所有调用都将在字段名称和年龄上应用过滤器(换句话说,对 web api 的所有调用都将具有相同的模式,即如上所示)也就是说,我们必须决定以下哪些索引提供最佳性能:
复合索引:name: 1, age: 1
两个单字段索引:name: 1
和 age: 1
根据一些简单的测试,似乎单个复合索引比两个单字段索引性能要好得多。
通过 mongo shell 执行单个查询,explain() 方法表明使用单个复合索引可以比使用两个单字段索引快近十倍地查询数据库。
在更现实的情况下,这种差异似乎不那么明显,在这种情况下,不是通过 mongo shell 执行单个查询,而是对 nodejs Web 应用程序的两个不同 url 进行多次调用。两个 url 都对数据库执行查询并将获取的数据作为 json 数组返回,一个使用具有单个复合索引的集合,另一个使用具有两个单字段索引的集合(两个集合具有完全相同的文档)。 在本次测试中,单一复合指数在性能方面似乎仍然是最佳选择,但这次差异不那么明显。
根据测试结果,我们正在考虑使用单一复合指数法。
有没有人有这方面的经验?我们是否遗漏了任何重要的考虑因素(可能是大型复合索引的一些缺点)?
【问题讨论】:
【参考方案1】:给定一个简单的标准查询(没有limit()
或sort()
或任何花哨的应用),它在两个字段上具有过滤条件(如您的示例中的name
和age
),以便找到生成的文档,MongoDB 将:
-
做一个完整的集合扫描(读取整个集合中的每个文档,解析 BSON,找到有问题的值,根据输入测试它们并返回/丢弃每个文档):这太棒了I/O 密集,因此很慢。
使用一个索引来保存其中一个字段(使用索引树来定位相关的文档子集,然后对其进行扫描):根据您的数据分布/索引selectivity,这可以是非常快或几乎没有任何好处(想象一下在一个包含 30 到 40 岁之间数百万人的数据集中的
age
上的索引 --> 每次查找仍然会产生无穷无尽的文档)。
使用两个索引,它们一起包含两个相关字段(加载两个索引,执行键查找,然后计算结果的intersection):同样,根据您的数据分布,这可能或者可能不会给你更好的(呃)性能。但是,在大多数情况下,它应该比#2 更快。但是,如果它真的比 #4 慢 10 倍(正如您所提到的),我会感到惊讶。
使用 compound index(随后的两个键查找立即导致所需的文档):这将是所有选项中最快的选择,因为它需要最少和最便宜的操作才能找到正确的文件。为了确保最大程度的重用(而不是不会受此影响的性能),您通常应该首先从最具选择性的字段开始,所以在您的情况下,可能是name
而不是age
考虑到很多的人与name
(更高的选择性)相比,会有相同的age
(选择性太低)。但该选择还取决于您的具体场景以及您打算对数据库运行的查询。网上有一篇很好的文章,介绍了如何最好地定义复合索引,同时考虑到您的具体情况的各个方面:https://emptysqua.re/blog/optimizing-mongodb-compound-indexes
要考虑的其他方面包括: 索引更新需要付出一定的代价。但是,如果您只关心原始读取速度,并且时不时地只有一些更新,那么您应该选择更多/更大的索引。
最后但并非最不重要的(!)过度使用的底线建议:使用真实数据甚至可能是真实的负载场景来分析您的系统。并且随着您的数据/系统随时间的变化而不断进行测量。
附加内容: https://docs.mongodb.com/manual/core/query-optimization/index.html
https://dba.stackexchange.com/questions/158240/mongodb-index-intersection-does-not-eliminate-the-need-for-creating-compound-in
Index intersection vs. compound index?
mongodb compund index vs. index intersect
How does the order of compound indexes matter in MongoDB performance-wise?
In MongoDB, I am using a large query, how I will create compound index or single index, So My response time boost up
【讨论】:
确实非常有用!您能否在第 4 点中澄清Important here is to start with the most selective field first
的含义?在查询中,OP 同时查询了name
和age
(在同一个查询中)。你是说使用find(name: "Bob", age: 25)
比使用find(age: 25, name: "Bob")
更快,因为name
具有更高的选择性?
@YSK:不会。性能不会因此而改变。我已更新我的答案以澄清此声明。
@dnickless 那么如果订单字段不同,您的意思是One compound index: name: 1, age: 1
比Two single-field indexes: name: 1 and age: 1
慢吗?
另外非常感谢您提供的文章。尽管已经是 2021 年,但它仍然是非常有用的信息,大量与索引相关的文章。谢谢!以上是关于MongoDB Find 性能:单个复合索引 VS 两个单字段索引的主要内容,如果未能解决你的问题,请参考以下文章