MongoDB中索引怎么用

55次阅读
没有评论

共计 10135 个字符,预计需要花费 26 分钟才能阅读完成。

丸趣 TV 小编给大家分享一下 MongoDB 中索引怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

在任何数据库之中,索引都是一种提升数据库检索性能的手段。
MongoDB 数据库里面依然会存在两种索引创建:一种是自动创建,另外一种是手工创建。

范例:重新准备一个新的简单集合。
db.emp.drop();
db.emp.insert({name : 赵一 , sex : 男 , age :30, sal :1000, loc : 北京});
db.emp.insert({name : 钱二 , sex : 女 , age :22, sal :5000, loc : 上海});
db.emp.insert({name : 孙三 , sex : 男 , age :40, sal :2000, loc : 深圳});
db.emp.insert({name : 李四 , sex : 女 , age :30, sal :7000, loc : 北京});
db.emp.insert({name : 周五 , sex : 女 , age :30, sal :6400, loc : 北京});
db.emp.insert({name : 吴六 , sex : 男 , age :30, sal :2500, loc : 重庆});
db.emp.insert({name : 郑七 , sex : 女 , age :50, sal :4700, loc : 成都});
db.emp.insert({name : 王八 , sex : 男 , age :35, sal :8000, loc : 北京});

此时在 emp 的集合上并没有去设置任何的索引,可以通过 getIndexes()函数来观察在 emp 集合中的索引。

范例:查询默认状态下 emp 集合的索引内容
db.emp.getIndexes();
[
  {
  v : 2,
  key : {
  _id : 1
  },
  name : _id_ ,
  ns : hr.emp
  }
]

现在发现会存在有一个“_id”列的索引内容。但是如果要想创建自己的索引,则可以使用如下的语法:
索引创建:db. 集合名称.createIndex({列:1})
设置的 1 表示索引按照升序的方式进行排序,如果使用降序则使用“-1”

范例:创建一个索引,在 age 字段上设置一个降序索引
db.emp.createIndex({age :-1})
{
  createdCollectionAutomatically : false,
  numIndexesBefore : 1,
  numIndexesAfter : 2,
  ok : 1
此时并没有设置索引的名字,所以名字是自动命名的。命名的规范:“字段名称_索引的排序模式”
db.emp.getIndexes();
[
  {
  v : 2,
  key : {
  _id : 1
  },
  name : _id_ ,
  ns : hr.emp
  },
  {
  v : 2,
  key : {
  age : -1
  },
  name : age_-1 ,
  ns : hr.emp
  }
]

范例:针对于当前的 age 字段上的索引做一个分析
db.emp.find({age :30}).explain(executionStats
{
  queryPlanner : {
  plannerVersion : 1,
  namespace : hr.emp ,
  indexFilterSet : false,
  parsedQuery : {
  age : {
  $eq : 30
  }
  },
  winningPlan : {
  stage : FETCH ,
  inputStage : {
  stage : IXSCAN ,
  keyPattern : {
  age : -1
  },
  indexName : age_-1 ,
  isMultiKey : false,
  multiKeyPaths : {
  age : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [30.0, 30.0]
  ]
  }
  }
  },
  rejectedPlans : []
  },
  executionStats : {
  executionSuccess : true,
  nReturned : 4,
  executionTimeMillis : 0,
  totalKeysExamined : 4,
  totalDocsExamined : 4,
  executionStages : {
  stage : FETCH ,
  nReturned : 4,
  executionTimeMillisEstimate : 0,
  works : 5,
  advanced : 4,
  needTime : 0,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  docsExamined : 4,
  alreadyHasObj : 0,
  inputStage : {
  stage : IXSCAN ,
  nReturned : 4,
  executionTimeMillisEstimate : 0,
  works : 5,
  advanced : 4,
  needTime : 0,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  keyPattern : {
  age : -1
  },
  indexName : age_-1 ,
  isMultiKey : false,
  multiKeyPaths : {
  age : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [30.0, 30.0]
  ]
  },
  keysExamined : 4,
  seeks : 1,
  dupsTested : 0,
  dupsDropped : 0,
  seenInvalidated : 0
  }
  }
  },
  serverInfo : {
  host : D2-LZY245 ,
  port : 27017,
  version : 3.4.7 ,
  gitVersion : cf38c1b8a0a8dca4a11737581beafef4fe120bcd
  },
  ok : 1
}

此时的查询使用了索引的技术,但是下面再来观察一个查询,不使用索引字段

范例:针对于 sal 字段进行查询
db.emp.find({sal :{ $gt :5000}}).explain(executionStats
{
  queryPlanner : {
  plannerVersion : 1,
  namespace : hr.emp ,
  indexFilterSet : false,
  parsedQuery : {
  sal : {
  $gt : 5000
  }
  },
  winningPlan : {
  stage : COLLSCAN ,
  filter : {
  sal : {
  $gt : 5000
  }
  },
  direction : forward
  },
  rejectedPlans : []
  },
  executionStats : {
  executionSuccess : true,
  nReturned : 3,
  executionTimeMillis : 0,
  totalKeysExamined : 0,
  totalDocsExamined : 8,
  executionStages : {
  stage : COLLSCAN ,
  filter : {
  sal : {
  $gt : 5000
  }
  },
  nReturned : 3,
  executionTimeMillisEstimate : 0,
  works : 10,
  advanced : 3,
  needTime : 6,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  direction : forward ,
  docsExamined : 8
  }
  },
  serverInfo : {
  host : D2-LZY245 ,
  port : 27017,
  version : 3.4.7 ,
  gitVersion : cf38c1b8a0a8dca4a11737581beafef4fe120bcd
  },
  ok : 1
}
此时在 sal 字段上并没有设置索引,所以当前的索引形式就变成了全集合扫描的模式。
但是如果说,现在换一种形式,年龄和薪水一起执行查询:
db.emp.find({age :30, sal :7000}).explain(executionStats)
{
  queryPlanner : {
  plannerVersion : 1,
  namespace : hr.emp ,
  indexFilterSet : false,
  parsedQuery : {
  $and : [
  {
  age : {
  $eq : 30
  }
  },
  {
  sal : {
  $eq : 7000
  }
  }
  ]
  },
  winningPlan : {
  stage : FETCH ,
  filter : {
  sal : {
  $eq : 7000
  }
  },
  inputStage : {
  stage : IXSCAN ,
  keyPattern : {
  age : -1
  },
  indexName : age_-1 ,
  isMultiKey : false,
  multiKeyPaths : {
  age : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [30.0, 30.0]
  ]
  }
  }
  },
  rejectedPlans : []
  },
  executionStats : {
  executionSuccess : true,
  nReturned : 1,
  executionTimeMillis : 0,
  totalKeysExamined : 4,
  totalDocsExamined : 4,
  executionStages : {
  stage : FETCH ,
  filter : {
  sal : {
  $eq : 7000
  }
  },
  nReturned : 1,
  executionTimeMillisEstimate : 0,
  works : 5,
  advanced : 1,
  needTime : 3,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  docsExamined : 4,
  alreadyHasObj : 0,
  inputStage : {
  stage : IXSCAN ,
  nReturned : 4,
  executionTimeMillisEstimate : 0,
  works : 5,
  advanced : 4,
  needTime : 0,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  keyPattern : {
  age : -1
  },
  indexName : age_-1 ,
  isMultiKey : false,
  multiKeyPaths : {
  age : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [30.0, 30.0]
  ]
  },
  keysExamined : 4,
  seeks : 1,
  dupsTested : 0,
  dupsDropped : 0,
  seenInvalidated : 0
  }
  }
  },
  serverInfo : {
  host : D2-LZY245 ,
  port : 27017,
  version : 3.4.7 ,
  gitVersion : cf38c1b8a0a8dca4a11737581beafef4fe120bcd
  },
  ok : 1
}
这个时候虽然 age 字段上面存在索引,由于 sal 字段上面没有索引,所以依然使用的是全表扫描操作。为了解决此时的问题,可以使用一个复合索引。
db.emp.createIndex({age :-1, sal :-1},{name: age_-1_sal_-1_index})
{
  createdCollectionAutomatically : false,
  numIndexesBefore : 2,
  numIndexesAfter : 3,
  ok : 1
}

范例:默认使用索引
db.emp.find({age :30, sal :7000}).explain(executionStats)
{
  queryPlanner : {
  plannerVersion : 1,
  namespace : hr.emp ,
  indexFilterSet : false,
  parsedQuery : {
  $and : [
  {
  age : {
  $eq : 30
  }
  },
  {
  sal : {
  $eq : 7000
  }
  }
  ]
  },
  winningPlan : {
  stage : FETCH ,
  inputStage : {
  stage : IXSCAN ,
  keyPattern : {
  age : -1,
  sal : -1
  },
  indexName : age_-1_sal_-1_index ,
  isMultiKey : false,
  multiKeyPaths : {
  age : [],
  sal : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [30.0, 30.0]
  ],
  sal : [
  [7000.0, 7000.0]
  ]
  }
  }
  },
  rejectedPlans : [
  {
  stage : FETCH ,
  filter : {
  sal : {
  $eq : 7000
  }
  },
  inputStage : {
  stage : IXSCAN ,
  keyPattern : {
  age : -1
  },
  indexName : age_-1 ,
  isMultiKey : false,
  multiKeyPaths : {
  age : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [30.0, 30.0]
  ]
  }
  }
  }
  ]
  },
  executionStats : {
  executionSuccess : true,
  nReturned : 1,
  executionTimeMillis : 0,
  totalKeysExamined : 1,
  totalDocsExamined : 1,
  executionStages : {
  stage : FETCH ,
  nReturned : 1,
  executionTimeMillisEstimate : 0,
  works : 3,
  advanced : 1,
  needTime : 0,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  docsExamined : 1,
  alreadyHasObj : 0,
  inputStage : {
  stage : IXSCAN ,
  nReturned : 1,
  executionTimeMillisEstimate : 0,
  works : 2,
  advanced : 1,
  needTime : 0,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  keyPattern : {
  age : -1,
  sal : -1
  },
  indexName : age_-1_sal_-1_index ,
  isMultiKey : false,
  multiKeyPaths : {
  age : [],
  sal : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [30.0, 30.0]
  ],
  sal : [
  [7000.0, 7000.0]
  ]
  },
  keysExamined : 1,
  seeks : 1,
  dupsTested : 0,
  dupsDropped : 0,
  seenInvalidated : 0
  }
  }
  },
  serverInfo : {
  host : D2-LZY245 ,
  port : 27017,
  version : 3.4.7 ,
  gitVersion : cf38c1b8a0a8dca4a11737581beafef4fe120bcd
  },
  ok : 1
}

但是如果换到了以下条件:
db.emp.find({$or :[{ age :{ $gt :30}},{sal :{ $gt :5000}}]}).explain(executionStats)
{
  queryPlanner : {
  plannerVersion : 1,
  namespace : hr.emp ,
  indexFilterSet : false,
  parsedQuery : {
  $or : [
  {
  age : {
  $gt : 30
  }
  },
  {
  sal : {
  $gt : 5000
  }
  }
  ]
  },
  winningPlan : {
  stage : SUBPLAN ,
  inputStage : {
  stage : COLLSCAN ,
  filter : {
  $or : [
  {
  age : {
  $gt : 30
  }
  },
  {
  sal : {
  $gt : 5000
  }
  }
  ]
  },
  direction : forward
  }
  },
  rejectedPlans : []
  },
  executionStats : {
  executionSuccess : true,
  nReturned : 5,
  executionTimeMillis : 0,
  totalKeysExamined : 0,
  totalDocsExamined : 8,
  executionStages : {
  stage : SUBPLAN ,
  nReturned : 5,
  executionTimeMillisEstimate : 0,
  works : 10,
  advanced : 5,
  needTime : 4,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  inputStage : {
  stage : COLLSCAN ,
  filter : {
  $or : [
  {
  age : {
  $gt : 30
  }
  },
  {
  sal : {
  $gt : 5000
  }
  }
  ]
  },
  nReturned : 5,
  executionTimeMillisEstimate : 0,
  works : 10,
  advanced : 5,
  needTime : 4,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  direction : forward ,
  docsExamined : 8
  }
  }
  },
  serverInfo : {
  host : D2-LZY245 ,
  port : 27017,
  version : 3.4.7 ,
  gitVersion : cf38c1b8a0a8dca4a11737581beafef4fe120bcd
  },
  ok : 1
}

现在发现并没有使用索引,所以这个时候看能否强制使用一次索引:hint()函数为强制使用索引操作。
范例:强制使用索引
db.emp.find({$or :[{ age :{ $gt :50}},{sal :{ $gt :3000}}]}).hint(age_-1_sal_-1_index).explain(executionStats)
{
  queryPlanner : {
  plannerVersion : 1,
  namespace : hr.emp ,
  indexFilterSet : false,
  parsedQuery : {
  $or : [
  {
  age : {
  $gt : 50
  }
  },
  {
  sal : {
  $gt : 3000
  }
  }
  ]
  },
  winningPlan : {
  stage : FETCH ,
  filter : {
  $or : [
  {
  age : {
  $gt : 50
  }
  },
  {
  sal : {
  $gt : 3000
  }
  }
  ]
  },
  inputStage : {
  stage : IXSCAN ,
  keyPattern : {
  age : -1,
  sal : -1
  },
  indexName : age_-1_sal_-1_index ,
  isMultiKey : false,
  multiKeyPaths : {
  age : [],
  sal : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [MaxKey, MinKey]
  ],
  sal : [
  [MaxKey, MinKey]
  ]
  }
  }
  },
  rejectedPlans : []
  },
  executionStats : {
  executionSuccess : true,
  nReturned : 5,
  executionTimeMillis : 0,
  totalKeysExamined : 8,
  totalDocsExamined : 8,
  executionStages : {
  stage : FETCH ,
  filter : {
  $or : [
  {
  age : {
  $gt : 50
  }
  },
  {
  sal : {
  $gt : 3000
  }
  }
  ]
  },
  nReturned : 5,
  executionTimeMillisEstimate : 0,
  works : 9,
  advanced : 5,
  needTime : 3,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  docsExamined : 8,
  alreadyHasObj : 0,
  inputStage : {
  stage : IXSCAN ,
  nReturned : 8,
  executionTimeMillisEstimate : 0,
  works : 9,
  advanced : 8,
  needTime : 0,
  needYield : 0,
  saveState : 0,
  restoreState : 0,
  isEOF : 1,
  invalidates : 0,
  keyPattern : {
  age : -1,
  sal : -1
  },
  indexName : age_-1_sal_-1_index ,
  isMultiKey : false,
  multiKeyPaths : {
  age : [],
  sal : []
  },
  isUnique : false,
  isSparse : false,
  isPartial : false,
  indexVersion : 2,
  direction : forward ,
  indexBounds : {
  age : [
  [MaxKey, MinKey]
  ],
  sal : [
  [MaxKey, MinKey]
  ]
  },
  keysExamined : 8,
  seeks : 1,
  dupsTested : 0,
  dupsDropped : 0,
  seenInvalidated : 0
  }
  }
  },
  serverInfo : {
  host : D2-LZY245 ,
  port : 27017,
  version : 3.4.7 ,
  gitVersion : cf38c1b8a0a8dca4a11737581beafef4fe120bcd
  },
  ok : 1
}

如果正常来讲,这个代码根本就不可能调用默认的索引执行,如果需要可以使用 hint()函数强制 MongoDB 必须使用索引。
如果在一个集合里面设置了过多的索引,实际上会导致性能下降。那么可以删除索引。

范例:删除一个索引
db.emp.dropIndex(age_-1_sal_-1_index)
{nIndexesWas : 3, ok : 1}
db.emp.getIndexes();
[
  {
  v : 2,
  key : {
  _id : 1
  },
  name : _id_ ,
  ns : hr.emp
  },
  {
  v : 2,
  key : {
  age : -1
  },
  name : age_-1 ,
  ns : hr.emp
  }
]

范例:删除非 _id 的索引,也就是自定义的索引
db.emp.dropIndexes();
{
  nIndexesWas : 2,
  msg : non-_id indexes dropped for collection ,
  ok : 1
}
db.emp.getIndexes();
[
  {
  v : 2,
  key : {
  _id : 1
  },
  name : _id_ ,
  ns : hr.emp
  }
]
以上是“MongoDB 中索引怎么用”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注丸趣 TV 行业资讯频道!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-20发表,共计10135字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)