当没有指定排序顺序时,MongoDB如何对记录进行排序?

154

当我们在Mongo中运行一个没有指定任何排序顺序的find()查询时,数据库内部使用什么来对结果进行排序?

根据mongo网站上的文档:

执行没有参数的find()时,数据库以正向自然顺序返回对象。

对于标准表,自然顺序并不特别有用,因为虽然顺序通常接近插入顺序,但不能保证是这样的。但是,对于Capped Collections,自然顺序保证是插入顺序。这非常有用。

然而,对于标准集合(非capped collections),用于对结果进行排序的字段是什么?是_id字段还是其他字段?

编辑:

基本上,我想要了解的是如果我执行以下搜索查询:

db.collection.find({"x":y}).skip(10000).limit(1000);

在不同的时间点t1t2,以下情况会得到不同的结果:

  1. t1和t2之间没有其他写入操作时?
  2. t1和t2之间有新的写入操作时?
  3. t1和t2之间添加了新的索引时?

我已经在临时数据库上运行了一些测试,对于所有三种情况,我的测试结果都相同(),但我想要确认并且我确定我的测试案例并不是非常全面。

2个回答

165
默认排序顺序是什么,当没有指定时?
默认的内部排序顺序(或自然顺序)是一个未定义的实现细节。维护顺序对于存储引擎来说是额外的开销,MongoDB的API并不要求在显式的排序(sort())或者聚集集合和固定大小的封顶集合的特殊情况之外保证可预测性。
对于典型的工作负载,希望存储引擎尝试重用可用的预分配空间,并决定如何在磁盘和内存中最高效地存储数据。在没有任何查询条件的情况下,结果将由存储引擎按照自然顺序返回(即按照它们被找到的顺序)。结果顺序可能与插入顺序一致,但这种行为不能保证,也不能依赖(除了聚集集合或封顶集合)。
一些可能影响存储(自然)顺序的示例:
- WiredTiger在磁盘上与内存缓存中使用不同的文档表示,因此自然顺序可能会根据内部数据结构而改变。 - 原始的MMAPv1存储引擎(在MongoDB 4.2中已移除)根据填充规则为文档分配记录空间。如果文档超出当前分配的记录空间,文档位置(和自然顺序)将受到影响。由于删除或移动的文档,新文档也可以插入到标记为可重用的存储中。 - 复制使用idempotent oplog格式来一致地应用写操作到副本集成员。每个副本集成员维护本地数据文件,这些文件的自然顺序可能不同,但在应用oplog更新时将具有相同的数据结果。
如果使用索引,文档将按照它们被找到的顺序返回(这不一定与插入顺序或I/O顺序相匹配)。如果使用多个索引,则顺序在内部取决于哪个索引在去重过程中首先识别到文档。
如果你想要一个可预测的排序顺序,你必须在查询中包含一个明确的sort(),并且对于排序键,必须有唯一的值。
限制集合如何保持插入顺序?
对于限制集合中的自然顺序,实施异常是通过它们的特殊使用限制来强制执行的:文档按插入顺序存储,但现有文档的大小不能增加,也不能显式删除文档。排序是限制集合设计的一部分,确保最旧的文档首先“过时”。
聚集集合(MongoDB 5.3+)
从MongoDB 5.3开始,可以创建一个集群集合,其中文档按照_id索引键值进行排序。在创建集合时必须声明clusteredIndex。集群集合有一些使用限制,但可以提高对集群索引键的范围扫描和相等比较的查询性能。

4
这是否意味着,如果我在两个不同的时间点运行相同的查找命令:db.collection.find({"x":y}).skip(20000).limit(1000),我会得到不同的结果集?如果这两个命令之间没有写入操作会发生什么? - saurabhj
7
@saurabhj: 增加了一些会影响自然顺序的示例。如果文档已被移动/删除,您可能会获得不同的结果集。如果没有插入/更新/删除文档,则应该获得相同的结果。添加索引不会影响磁盘上文档的位置。 - Stennie
8
还需注意,如果您正在使用复制,则各个副本集成员之间的自然排序可能会有所不同。 - Stennie
有人知道如何强制执行这里注释的任意两个点吗?我们尝试修改文档,但它们仍然按照插入顺序返回...我很好奇自然顺序是否可以与插入顺序不同。 - Ferran Maylinch
强制默认顺序(例如 {createdAt:-1})是实现乐观 UI 模式(在创建/更新/删除后不等待服务器响应即可更新缓存中的数据列表)所必需的。否则,您无法匹配客户端乐观顺序和服务器响应顺序。 - Eric Burel
1
请访问https://www.mongodb.com/docs/v6.0/core/clustered-collections/以查看翻译后的文本。 - undefined

16

它按照存储的顺序返回(文件中的顺序),但不能保证它们是按照插入的顺序排列的。它们没有按_id字段排序。有时看起来像是按照插入顺序排序,但在另一个请求中可能会改变。这不是可靠的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接