广告
返回顶部
首页 > 资讯 > 数据库 >MongoDB中如何使用复合索引
  • 751
分享到

MongoDB中如何使用复合索引

2024-04-02 19:04:59 751人浏览 独家记忆
摘要

本篇文章给大家分享的是有关mongoDB中如何使用复合索引,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。什么是复合索引?复合索引,即Compo

本篇文章给大家分享的是有关mongoDB中如何使用复合索引,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

什么是复合索引?

复合索引,即Compound Index,指的是将多个键组合到一起创建索引,这样可以加速匹配多个键的查询。不妨通过一个简单的示例理解复合索引。

students集合如下:

db.students.find().pretty()
{
 "_id" : ObjectId("5aa7390ca5be7272a99b042a"),
 "name" : "zhang",
 "age" : "15"
}
{
 "_id" : ObjectId("5aa7393ba5be7272a99b042b"),
 "name" : "wang",
 "age" : "15"
}
{
 "_id" : ObjectId("5aa7393ba5be7272a99b042c"),
 "name" : "zhang",
 "age" : "14"
}

在name和age两个键分别创建了索引(_id自带索引):

db.students.getIndexes()
[
 {
 "v" : 1,
 "key" : {
 "name" : 1
 },
 "name" : "name_1",
 "ns" : "test.students"
 },
 {
 "v" : 1,
 "key" : {
 "age" : 1
 },
 "name" : "age_1",
 "ns" : "test.students"
 }
]

当进行多键查询时,可以通过explian()分析执行情况(结果仅保留winningPlan):

db.students.find({name:"zhang",age:"14"}).explain()
"winningPlan":
{
 "stage": "FETCH",
 "filter":
 {
  "name":
  {
   "$eq": "zhang"
  }
 },
 "inputStage":
 {
  "stage": "IXSCAN",
  "keyPattern":
  {
   "age": 1
  },
  "indexName": "age_1",
  "isMultiKey": false,
  "isUnique": false,
  "isSparse": false,
  "isPartial": false,
  "indexVersion": 1,
  "direction": "forward",
  "indexBounds":
  {
   "age": [
    "[\"14\", \"14\"]"
   ]
  }
 }
}

由winningPlan可知,这个查询依次分为IXSCAN和FETCH两个阶段。IXSCAN即索引扫描,使用的是age索引;FETCH即根据索引去查询文档,查询的时候需要使用name进行过滤。

为name和age创建复合索引:

db.students.createIndex({name:1,age:1})
db.students.getIndexes()
[
 {
 "v" : 1,
 "key" : {
 "name" : 1,
 "age" : 1
 },
 "name" : "name_1_age_1",
 "ns" : "test.students"
 }
]

有了复合索引之后,同一个查询的执行方式就不同了:

db.students.find({name:"zhang",age:"14"}).explain()
"winningPlan":
{
 "stage": "FETCH",
 "inputStage":
 {
  "stage": "IXSCAN",
  "keyPattern":
  {
   "name": 1,
   "age": 1
  },
  "indexName": "name_1_age_1",
  "isMultiKey": false,
  "isUnique": false,
  "isSparse": false,
  "isPartial": false,
  "indexVersion": 1,
  "direction": "forward",
  "indexBounds":
  {
   "name": [
    "[\"zhang\", \"zhang\"]"
   ],
   "age": [
    "[\"14\", \"14\"]"
   ]
  }
 }
}

由winningPlan可知,这个查询的顺序没有变化,依次分为IXSCAN和FETCH两个阶段。但是,IXSCAN使用的是name与age的复合索引;FETCH即根据索引去查询文档,不需要过滤。

这个示例的数据量太小,并不能看出什么问题。但是实际上,当数据量很大,IXSCAN返回的索引比较多时,FETCH时进行过滤将非常耗时。接下来将介绍一个真实的案例。

定位MongoDB性能问题

随着接收的错误数据不断增加,我们Fundebug已经累计处理3.5亿错误事件,这给我们的服务不断带来性能方面的挑战,尤其对于MonGoDB集群来说。

对于生产数据库,配置profile,可以记录MongoDB的性能数据。执行以下命令,则所有超过1s的数据库读写操作都会被记录下来。

db.setProfilingLevel(1,1000)

查询profile所记录的数据,会发现events集合的某个查询非常慢:

db.system.profile.find().pretty()
{
 "op" : "command",
 "ns" : "fundebug.events",
 "command" : {
 "count" : "events",
 "query" : {
 "createAt" : {
 "$lt" : ISODate("2018-02-05T20:30:00.073Z")
 },
 "projectId" : ObjectId("58211791ea2640000c7a3fe6")
 }
 },
 "keyUpdates" : 0,
 "writeConflicts" : 0,
 "numYield" : 1414,
 "locks" : {
 "Global" : {
 "acquireCount" : {
 "r" : NumberLong(2830)
 }
 },
 "Database" : {
 "acquireCount" : {
 "r" : NumberLong(1415)
 }
 },
 "Collection" : {
 "acquireCount" : {
 "r" : NumberLong(1415)
 }
 }
 },
 "responseLength" : 62,
 "protocol" : "op_query",
 "millis" : 28521,
 "execStats" : {
 },
 "ts" : ISODate("2018-03-07T20:30:59.440Z"),
 "client" : "192.168.59.226",
 "allUsers" : [ ],
 "user" : ""
}

events集合中有数亿个文档,因此count操作比较慢也不算太意外。根据profile数据,这个查询耗时28.5s,时间长得有点离谱。另外,numYield高达1414,这应该就是操作如此之慢的直接原因。根据MongoDB文档,numYield的含义是这样的:

The number of times the operation yielded to allow other operations to complete. Typically, operations yield when they need access to data that MongoDB has not yet fully read into memory. This allows other operations that have data in memory to complete while MongoDB reads in data for the yielding operation.

这就意味着大量时间消耗在读取硬盘上,且读了非常多次。可以推测,应该是索引的问题导致的。

不妨使用explian()来分析一下这个查询(仅保留executionStats):

db.events.explain("executionStats").count({"projectId" : ObjectId("58211791ea2640000c7a3fe6"),createAt:{"$lt" : ISODate("2018-02-05T20:30:00.073Z")}})
"executionStats":
{
 "executionSuccess": true,
 "nReturned": 20853,
 "executionTimeMillis": 28055,
 "totalKeysExamined": 28338,
 "totalDocsExamined": 28338,
 "executionStages":
 {
  "stage": "FETCH",
  "filter":
  {
   "createAt":
   {
    "$lt": ISODate("2018-02-05T20:30:00.073Z")
   }
  },
  "nReturned": 20853,
  "executionTimeMillisEstimate": 27815,
  "works": 28339,
  "advanced": 20853,
  "needTime": 7485,
  "needYield": 0,
  "saveState": 1387,
  "restoreState": 1387,
  "isEOF": 1,
  "invalidates": 0,
  "docsExamined": 28338,
  "alreadyHasObj": 0,
  "inputStage":
  {
   "stage": "IXSCAN",
   "nReturned": 28338,
   "executionTimeMillisEstimate": 30,
   "works": 28339,
   "advanced": 28338,
   "needTime": 0,
   "needYield": 0,
   "saveState": 1387,
   "restoreState": 1387,
   "isEOF": 1,
   "invalidates": 0,
   "keyPattern":
   {
    "projectId": 1
   },
   "indexName": "projectId_1",
   "isMultiKey": false,
   "isUnique": false,
   "isSparse": false,
   "isPartial": false,
   "indexVersion": 1,
   "direction": "forward",
   "indexBounds":
   {
    "projectId": [
     "[ObjectId('58211791ea2640000c7a3fe6'), ObjectId('58211791ea2640000c7a3fe6')]"
    ]
   },
   "keysExamined": 28338,
   "dupsTested": 0,
   "dupsDropped": 0,
   "seenInvalidated": 0
  }
 }
}

可知,events集合并没有为projectId与createAt建立复合索引,因此IXSCAN阶段采用的是projectId索引,其nReturned为28338; FETCH阶段需要根据createAt进行过滤,其nReturned为20853,过滤掉了7485个文档;另外,IXSCAN与FETCH阶段的executionTimeMillisEstimate分别为30ms和27815ms,因此基本上所有时间都消耗在了FETCH阶段,这应该是读取硬盘导致的。

创建复合索引

没有为projectId和createAt创建复合索引是个尴尬的错误,赶紧补救一下:

db.events.createIndex({projectId:1,createTime:-1},{background: true})

在生产环境构建索引这种事最好是晚上做,这个命令一共花了大概7个小时吧!background设为true,指的是不要阻塞数据库的其他操作,保证数据库的可用性。但是,这个命令会一直占用着终端,这时不能使用CTRL + C,否则会终止索引构建过程。

复合索引创建成果之后,前文的查询就快了很多(仅保留executionStats):

db.javascriptevents.explain("executionStats").count({"projectId" : ObjectId("58211791ea2640000c7a3fe6"),createAt:{"$lt" : ISODate("2018-02-05T20:30:00.073Z")}})
"executionStats":
{
 "executionSuccess": true,
 "nReturned": 0,
 "executionTimeMillis": 47,
 "totalKeysExamined": 20854,
 "totalDocsExamined": 0,
 "executionStages":
 {
  "stage": "COUNT",
  "nReturned": 0,
  "executionTimeMillisEstimate": 50,
  "works": 20854,
  "advanced": 0,
  "needTime": 20853,
  "needYield": 0,
  "saveState": 162,
  "restoreState": 162,
  "isEOF": 1,
  "invalidates": 0,
  "nCounted": 20853,
  "nSkipped": 0,
  "inputStage":
  {
   "stage": "COUNT_SCAN",
   "nReturned": 20853,
   "executionTimeMillisEstimate": 50,
   "works": 20854,
   "advanced": 20853,
   "needTime": 0,
   "needYield": 0,
   "saveState": 162,
   "restoreState": 162,
   "isEOF": 1,
   "invalidates": 0,
   "keysExamined": 20854,
   "keyPattern":
   {
    "projectId": 1,
    "createAt": -1
   },
   "indexName": "projectId_1_createTime_-1",
   "isMultiKey": false,
   "isUnique": false,
   "isSparse": false,
   "isPartial": false,
   "indexVersion": 1
  }
 }
}

以上就是MongoDB中如何使用复合索引,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网数据库频道。

您可能感兴趣的文档:

--结束END--

本文标题: MongoDB中如何使用复合索引

本文链接: https://www.lsjlt.com/news/56466.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MongoDB中如何使用复合索引
    本篇文章给大家分享的是有关MongoDB中如何使用复合索引,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。什么是复合索引?复合索引,即Compo...
    99+
    2022-10-18
  • MongoDB中如何使用唯一索引
    这篇文章将为大家详细讲解有关MongoDB中如何使用唯一索引,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。我们用的是MongoDB数据存储用户信息,用户表中...
    99+
    2022-10-18
  • MongoDB数据库中如何使用索引
    本篇文章为大家展示了MongoDB数据库中如何使用索引,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。  MongoDB的各种索引有哪些用法  1.单列索引  在字段...
    99+
    2022-10-18
  • Oracle中如何创建复合索引
    这期内容当中小编将会给大家带来有关Oracle中如何创建复合索引,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。 1.对于复合索引,在Wher...
    99+
    2022-10-18
  • mysql复合索引如何创建
    在MySQL中,可以使用CREATE INDEX语句来创建复合索引。复合索引是基于多个列的索引,可以提高查询性能。 创建复合索引的语...
    99+
    2023-10-28
    mysql
  • Oracle中复合索引与空值的索引怎么用
    这篇文章给大家分享的是有关Oracle中复合索引与空值的索引怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在QQ群里讨论一个SQL优化的问题,语句大致如下:selec...
    99+
    2022-10-18
  • Mysql中复合索引使用规则有哪些
    这篇文章主要介绍了Mysql中复合索引使用规则有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。 联合索引验证:从左向右发挥作用索引:(...
    99+
    2022-10-18
  • MongoDB中怎么使用唯一索引
    这篇文章将为大家详细讲解有关MongoDB中怎么使用唯一索引,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。 唯一索引的主要目的是...
    99+
    2022-10-18
  • Mysql的复合索引如何生效
    目录背景认识复合索引最左匹配原则字段顺序的影响复合索引可以替代单一索引吗?小结背景 最近频繁出现慢SQL导致系统性能问题,于是决定针对索引进行一些优化。一些表结构本身已经有了不少索...
    99+
    2022-11-12
  • 复合索引使用的先决条件
    PS:懒得重新编辑图片了,直接把我从51上的日志拷过来了。背景:今天,接到一个项目的项目经理电话,告之说生产环境有几个查询超级慢,就是查询单张表的数据,查询条件也很简单,但是加了索引以后并没有走索引,依然还...
    99+
    2022-10-18
  • mongodb数据库中怎么使用索引
    这篇文章将为大家详细讲解有关mongodb数据库中怎么使用索引,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。      &nb...
    99+
    2022-10-18
  • MongoDB中怎么使用地理信息索引
    MongoDB中怎么使用地理信息索引,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 地理信息索引分...
    99+
    2022-10-18
  • mongodb中索引分类是怎样的以及如何创建索引
    mongodb中索引分类是怎样的以及如何创建索引,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。学习索引分类和创建索引:   &nbs...
    99+
    2022-10-18
  • 使用 MySQL 中的复合索引使慢速查询变得更快
    让我们首先看看什么是复合索引 -复合索引是在多个列上使用的索引。 也称为多列索引。MySQL 允许用户创建复合索引,该索引最多可以包含16 列。查询优化器使用复合索引进行查询,这将测试索引中的所有列。它也可用于测试第一列、前两列等的查询。如...
    99+
    2023-10-22
  • Mongodb中使用B树索引的原因是什么
    这篇文章给大家介绍Mongodb中使用B树索引的原因是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。  B树和B+树  开头,我们先回忆一下,B树和B+树的结构以及特点。  树内的...
    99+
    2022-10-18
  • MySQL中如何使用索引
    这篇文章给大家介绍MySQL中如何使用索引,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。mysql采用b+树的方式存储索引信息。b+树结构如下:说一下b+树的几个特点:叶子节点(最下面...
    99+
    2022-10-18
  • 如何使用SQL语句在MongoDB中进行索引创建和优化?
    如何使用SQL语句在MongoDB中进行索引创建和优化?摘要:在MongoDB中,使用SQL语句进行索引创建和优化是一种高效的方式来提高查询性能。本文将介绍如何使用SQL语句在MongoDB中进行索引的创建和优化,并提供具体的代码示例。引言...
    99+
    2023-12-17
    索引创建:create index 优化查询:query optimization 索引类型:index types
  • MongoDB中如何使用inMemory存储引擎
    本篇文章为大家展示了MongoDB中如何使用inMemory存储引擎,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、MongoDB的存储引擎概述存储引擎(Stor...
    99+
    2022-10-18
  • Unix系统中的索引功能与PHP如何结合使用?
    Unix系统是一种广泛使用的操作系统,而PHP是一种流行的编程语言。在Unix系统中,索引功能是非常重要的,它可以帮助用户更快地找到所需的文件和信息。在本文中,我们将讨论Unix系统中的索引功能以及如何在PHP中使用它。 一、Unix系统中...
    99+
    2023-10-16
    unix 索引 linux
  • 如何在 ASP 中使用索引?
    在 ASP 中使用索引是优化数据库性能的一个重要步骤。索引可以让数据库在查询数据时更快速地定位到需要的数据,从而提高查询效率。本文将介绍如何在 ASP 中使用索引。 一、什么是索引? 索引是一种数据结构,它可以让数据库系统更快速地定位到需要...
    99+
    2023-07-30
    数据类型 索引 框架
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作