考虑一个大约100万英镑的集合.具有以下架构的文档:

{
    _id: ObjectId(),
    Title: "",
    Description: "",
    Scheduling: {
        From: 20230202,
        To: 20230201,
        MagicValue: 12
    },
    Mandatory: true,
    Type: "None"
}

创建一个像这样包含多键索引值的复合索引会有什么可能的缺点吗?

{ _id: 1, Title: 1, Scheduling.From: 1 }

该文档仅在处理嵌套数组文档时引用了限制,并继续解释索引界限、创建规则等.如果你真的想一想,上面的虚拟文档真的可以表达为:

{
    _id: ObjectId(),
    Title: "",
    Description: "",
    Scheduling.From: 20230202,
    Scheduling.To: 20230201,
    Scheduling.MagicValue: 12,
    Mandatory: true,
    Type: "None"
}

而且在索引引擎处理它的方式方面也不会有太大的不同,因为"调度"内部文档应该像一个命名空间一样.所以我在这里问...对于相同的复合索引,后一个文档的行为是否与上面的第一个文档不同?谢谢:)

推荐答案

my comment的基础上展开,您描述的情况将是not,结果是指数为multikey (in MongoDB terminology).如文档中所述,多键索引产生于以下情况:

如果任何索引字段是数组,MongoDB会自动创建一个多键索引;您不需要显式指定多键类型.

文档中没有字段,因此索引的字段都不是array.通过下面的测试,我们可以证明索引不是多键的:

test> db.foo.drop()
false
test> db.foo.insert({ _id: ObjectId(), Title: "", Description: "", Scheduling: { From: 20230202, To: 20230201, MagicValue: 12 }, Mandatory: true, Type: "None" })
{
  acknowledged: true,
  insertedIds: { '0': ObjectId("649de6208c8616ab438dd397") }
}
test> db.foo.createIndex({ _id: 1, Title: 1, "Scheduling.From": 1 })
_id_1_Title_1_Scheduling.From_1
test> db.foo.find().hint("_id_1_Title_1_Scheduling.From_1").explain().queryPlanner.winningPlan.inputStage
{
  stage: 'IXSCAN',
  keyPattern: { _id: 1, Title: 1, 'Scheduling.From': 1 },
  indexName: '_id_1_Title_1_Scheduling.From_1',
  isMultiKey: false,
  multiKeyPaths: { _id: [], Title: [], 'Scheduling.From': [] },
  isUnique: false,
  isSparse: false,
  isPartial: false,
  indexVersion: 2,
  direction: 'forward',
  indexBounds: {
    _id: [ '[MinKey, MaxKey]' ],
    Title: [ '[MinKey, MaxKey]' ],
    'Scheduling.From': [ '[MinKey, MaxKey]' ]
  }
}

最具体地说,输出报告isMultiKey: false.

相比之下,以下是针对多键复合索引所报告的内容:

> db.foo.drop()
false
test> db.foo.insert({_id:1, x: [1,2,3] })
{ acknowledged: true, insertedIds: { '0': 1 } }
test> db.foo.createIndex({_id:1, x:1})
_id_1_x_1
test> db.foo.find().hint("_id_1_x_1").explain().queryPlanner.winningPlan.inputStage
{
  stage: 'IXSCAN',
  keyPattern: { _id: 1, x: 1 },
  indexName: '_id_1_x_1',
  isMultiKey: true,
  multiKeyPaths: { _id: [], x: [ 'x' ] },
  isUnique: false,
  isSparse: false,
  isPartial: false,
  indexVersion: 2,
  direction: 'forward',
  indexBounds: { _id: [ '[MinKey, MaxKey]' ], x: [ '[MinKey, MaxKey]' ] }
}

所以这considerations for multikey index bounds个都不适用于你的情况.

话虽如此,但还有一件事需要注意.您的索引以_id字段为前缀,根据MongoDB的定义,该字段是唯一的.如果您打算使用此索引的一个或多个查询在_id字段上具有相等条件,则必须强制数据库使用它.当前版本的MongoDB在任何时候看到这种情况都会默认使用默认的{ _id: 1 }索引.

我们可以看到,通过恢复所需的索引并运行.explain()个相关查询:

test> db.foo.drop()
false
test> db.foo.createIndex({ _id: 1, Title: 1, "Scheduling.From": 1 })
_id_1_Title_1_Scheduling.From_1
test> db.foo.find({_id: 123, Title: 456, "Scheduling.From": 789}).explain().queryPlanner.winningPlan
{
  stage: 'FETCH',
  filter: {
    '$and': [
      { 'Scheduling.From': { '$eq': 789 } },
      { Title: { '$eq': 456 } }
    ]
  },
  inputStage: {
    stage: 'IXSCAN',
    keyPattern: { _id: 1 },
    indexName: '_id_',
    isMultiKey: false,
    multiKeyPaths: { _id: [] },
    isUnique: true,
    isSparse: false,
    isPartial: false,
    indexVersion: 2,
    direction: 'forward',
    indexBounds: { _id: [ '[123, 123]' ] }
  }
}

通过.hint()强制使用索引表明,如果需要,可以使用(并且高效地使用)索引:

 test> db.foo.find({_id: 123, Title: 456, "Scheduling.From": 789}).hint("_id_1_Title_1_Scheduling.From_1").explain().queryPlanner.winningPlan
{
  stage: 'FETCH',
  inputStage: {
    stage: 'IXSCAN',
    keyPattern: { _id: 1, Title: 1, 'Scheduling.From': 1 },
    indexName: '_id_1_Title_1_Scheduling.From_1',
    isMultiKey: false,
    multiKeyPaths: { _id: [], Title: [], 'Scheduling.From': [] },
    isUnique: false,
    isSparse: false,
    isPartial: false,
    indexVersion: 2,
    direction: 'forward',
    indexBounds: {
      _id: [ '[123, 123]' ],
      Title: [ '[456, 456]' ],
      'Scheduling.From': [ '[789, 789]' ]
    }
  }
}

Mongodb相关问答推荐

如何从MongoDB集合中获取第一个和最后一个元素?

没有文档的MongoDB集合中的不一致,但当我执行count()时,它告诉我有15个文档

MongoDB-如何过滤和获取数组字段中的最新数据

如何获取键值对的对象,其中值仅具有 mongoDB 中的投影字段

Spring Boot 升级后未映射 Mongo 模板结果

找到一个用户,然后使用 MongoDB 根据他们的总分获得他们的排名

使用新字段插入数据或使用 updateOne mongodb 有条件地更新

Raft Vs MongoDB 初选

MongoDB 的 Java 语法

Mongoose 与 mongodb 如何返回刚刚保存的对象?

为 php 5.6 (XAMPP) 添加 mongodb 扩展

Python - Pymongo 插入和更新文档

java.lang.IncompatibleClassChangeError:Implementing class Mongo

在 MongoDB 中合并两个集合

Mongo按实际上是数字的字符串值排序

MongoError: The dollar ($) prefixed field '$push' in '$push' is not valid for storage

无法连接到远程服务器上的 mongo

如何在mongoose的嵌套填充中 Select 特定字段

带有索引字段的 MongoDB 正则表达式

开发人员必须采取哪些mental steps才能开始从 SQL 迁移到 NOSQL(CouchDB、Fathom DB、MongoDB 等)?