3

我最近为我的一个项目潜入了 mongodb。我一直在阅读索引,对于一个小集合,我知道这并不重要,但是当它增长时,如果没有正确的索引和查询,就会出现性能问题。

可以说我有这样的收藏

{user_id:1,slug:'one-slug'}
{user_id:1,slug:'another-slug'}
{user_id:2,slug:'one-slug'}
{user_id:3,slug:'just-a-slug}

我必须在哪里搜索我的收藏

user id == 1 and slug == 'one-slug'

在这个集合中,slug 对用户 ID 来说是唯一的。也就是说,用户 id 1 只能拥有一个值为“one-slug”的 slug。

我知道 user_id 由于它的高基数应该被优先考虑,但是 slug 呢?因为它在大多数时候也是独一无二的。我也无法围绕升序和降序索引,或者在这种情况下它将如何影响性能或我应该在这个集合中使用的正确顺序。

我读了一点,但我无法理解它,特别是对于我的场景。听到别人的声音会很棒。

4

2 回答 2

14

您可以将 MongoDB 单字段索引视为一个数组,其中包含指向文档位置的指针。例如,如果您有一个集合(请注意,序列是故意乱序的):

[collection]
1: {a:3, b:2}
2: {a:1, b:2}
3: {a:2, b:1}
4: {a:1, b:1}
5: {a:2, b:2}

单字段索引

现在,如果你这样做:

db.collection.createIndex({a:1})

索引大致如下:

[index a:1]
1: {a:1} --> 2, 4
2: {a:2} --> 3, 5
3: {a:3} --> 1

注意三个重要的事情:

  • 它是按a升序排列的
  • 每个入口指向相关文档所在的位置
  • 索引只记录a字段的值。该b字段根本不存在于索引中

因此,如果您执行以下查询:

db.collection.find().sort({a:1})

它所要做的就是从上到下遍历索引,获取并输出条目指向的文档。请注意,您还可以从底部遍历索引,例如:

db.collection.find().sort({a:-1})

唯一的区别是您反向遍历索引。

因为b根本不在索引中,所以在查询任何关于b.

复合指数

在复合索引中,例如:

db.collection.createIndex({a:1, b:1})

这意味着您a要先排序,然后再排序b。索引看起来像:

[index a:1, b:1]
1: {a:1, b:1} --> 4
2: {a:1, b:2} --> 2
3: {a:2, b:1} --> 3
4: {a:2, b:2} --> 5
5: {a:3, b:2} --> 1

注意:

  • 索引从a
  • 在每个里面a你都有一个排序的b
  • 您有 5 个索引条目,而在前面的单字段示例中只有 3 个

使用此索引,您可以执行如下查询:

db.collection.find({a:2}).sort({b:1})

它可以很容易地找到a:2然后将索引向前移动。鉴于该索引,您不能这样做

db.collection.find().sort({b:1})
db.collection.find({b:1})

在这两个查询中,您都不容易找到b,因为它遍布整个索引(即不在连续的条目中)。但是你可以这样做:

db.collection.find({a:2}).sort({b:-1})

因为您基本上可以找到它们的a:2位置,然后将b条目向后移动。

编辑:在评论中澄清@marcospgp 的问题:

{a:1, b:1}如果您从排序表的角度来看,使用索引来满足的可能性find({a:2}).sort({b:-1})实际上是有意义的。例如,索引{a:1, b:1}可以被认为是:

a | b
--|--
1 | 1
1 | 2
2 | 1
2 | 2
2 | 3
3 | 1
3 | 2

查找({a:2}).sort({b:1})

该指数{a:1, b:1}意味着sort by a, then within each a, sort the b values。如果您然后执行 a find({a:2}).sort({b:1}),则索引知道所有这些a=2都在哪里。在这个块中a=2b将按升序排序(根据索引规范),因此find({a:2}).sort({b:1})可以通过以下方式满足查询:

a | b
--|--
1 | 1
1 | 2
2 | 1 <-- walk this block forward to satisfy
2 | 2 <-- find({a:2}).sort({b:1})
2 | 3 <--
3 | 1
3 | 2

查找({a:2}).sort({b:-1})

由于索引可以向前或向后走,因此遵循了类似的过程,最后有一个小扭曲:

a | b
--|--
1 | 1
1 | 2
2 | 1  <-- walk this block backward to satisfy
2 | 2  <-- find({a:2}).sort({b:-1})
2 | 3  <--
3 | 1
3 | 2

索引可以向前或向后走的事实是使查询find({a:2}).sort({b:-1})能够使用索引的关键点{a:1, b:1}

查询规划器解释

您可以使用 . 查看查询计划程序的计划db.collection.explain().find(....)。基本上,如果您看到stageof COLLSCAN,则表示没有使用索引或可用于查询。有关命令输出的详细信息,请参阅解释结果

于 2018-07-05T05:47:16.207 回答
0

[由于缺乏声誉,无法发表评论]

索引方向仅在您进行排序时才重要。

不完全准确:某些查询可以使用特定的方向索引更快,即使查询本身不需要顺序(排序只是为了结果)。例如,具有日期条件的查询:搜索昨天订阅的用户在索引上使用 desc 方向会比使用 asc 方向或没有索引更快。

{user_id:1,slug:1} 和 {slug:1,user_id:1} 之间的区别

mongo 将过滤第一个字段,然后在索引中第一个字段匹配(等等...)的第二个字段上进行过滤。必须首先设置更严格的字段才能真正改进查询

于 2018-07-04T12:11:42.833 回答