搜索
首页数据库MongoDB带你聊聊MongoDB中丰富的索引类型

带你聊聊MongoDB中丰富的索引类型

Feb 17, 2022 am 10:58 AM
mongodb索引类型

本篇文章带你了解MongoDB,介绍一下MongoDB中丰富的索引类型,希望对大家有所帮助!

带你聊聊MongoDB中丰富的索引类型

MongoDB的索引和MySql的索引的作用和优化要遵循的原则基本相似,MySql索引类型基本可以区分为:

  • 单键索引 - 联合索引
  • 主键索引(聚簇索引) - 非主键索引(非聚簇索引)

MongoDB中除了这些基础的分类之外,还有一些特殊的索引类型,如: 数组索引 | 稀疏索引 | 地理空间索引 | TTL索引等.

为了下面方便测试我们使用脚本插入以下数据

for(var i = 0;i < 100000;i++){
    db.users.insertOne({
        username: "user"+i,
        age: Math.random() * 100,
        sex: i % 2,
        phone: 18468150001+i
    });
}

单键索引

单键索引即索引的字段只有一个,是最基础的索引方式.

在集合中使用username字段,创建一个单键索引,MongoDB会自动将这个索引命名为username_1

db.users.createIndex({username:1})
&#39;username_1&#39;

在创建索引后查看一下使用username字段的查询计划,stageIXSCAN代表使用使用了索引扫描

db.users.find({username:"user40001"}).explain()
{ 
   queryPlanner: 
   { 
     winningPlan: 
     { 
        ......
        stage: &#39;FETCH&#39;,
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { username: 1 },
           indexName: &#39;username_1&#39;,
           ......
        } 
     }
     rejectedPlans: [] ,
   },
   ......
   ok: 1 
}

        在索引优化的原则当中,有很重要的原则就是索引要建立在基数高的的字段上,所谓基数就是一个字段上不重复数值的个数,即我们在创建users集合时年龄出现的数值是0-99那么age这个字段将会有100个不重复的数值,即age字段的基数为100,而sex这个字段只会出现0 | 1这个两个值,即sex字段的基础是2,这是一个相当低的基数,在这种情况下,索引的效率并不高并且会导致索引失效.

下面就船舰一个sex字段索引,来查询执行计划会发现,查询时是走的全表扫描,而没有走相关索引.

db.users.createIndex({sex:1})
&#39;sex_1&#39;

db.users.find({sex:1}).explain()
{ 
  queryPlanner: 
  { 
     ......
     winningPlan: 
     { 
        stage: &#39;COLLSCAN&#39;,
        filter: { sex: { &#39;$eq&#39;: 1 } },
        direction: &#39;forward&#39; 
     },
     rejectedPlans: [] 
  },
  ......
  ok: 1 
}

联合索引

联合索引即索引上会有多个字段,下面使用agesex两个字段创建一个索引

db.users.createIndex({age:1,sex:1})
&#39;age_1_sex_1&#39;

然后我们使用这两个字段进行一次查询,查看执行计划,顺利地走了这条索引

db.users.find({age:23,sex:1}).explain()
{ 
  queryPlanner: 
  { 
     ......
     winningPlan: 
     { 
        stage: &#39;FETCH&#39;,
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { age: 1, sex: 1 },
           indexName: &#39;age_1_sex_1&#39;,
           .......
           indexBounds: { age: [ &#39;[23, 23]&#39; ], sex: [ &#39;[1, 1]&#39; ] } 
        } 
     },
     rejectedPlans: [], 
  },
  ......
  ok: 1 
 }

数组索引

数组索引就是对数组字段创建索引,也叫做多值索引,下面为了测试将users集合中的数据增加一部分数组字段.

db.users.updateOne({username:"user1"},{$set:{hobby:["唱歌","篮球","rap"]}})
......

创建数组索引并进行查看其执行计划,注意isMultiKey: true表示使用的索引是多值索引.

db.users.createIndex({hobby:1})
&#39;hobby_1&#39;

db.users.find({hobby:{$elemMatch:{$eq:"钓鱼"}}}).explain()
{ 
   queryPlanner: 
   { 
     ......
     winningPlan: 
     { 
        stage: &#39;FETCH&#39;,
        filter: { hobby: { &#39;$elemMatch&#39;: { &#39;$eq&#39;: &#39;钓鱼&#39; } } },
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { hobby: 1 },
           indexName: &#39;hobby_1&#39;,
           isMultiKey: true,
           multiKeyPaths: { hobby: [ &#39;hobby&#39; ] },
           ......
           indexBounds: { hobby: [ &#39;["钓鱼", "钓鱼"]&#39; ] } } 
         },
     rejectedPlans: [] 
  },
  ......
  ok: 1 
}

        数组索引相比于其它索引来说索引条目和体积必然呈倍数增加,例如平均每个文档的hobby数组的size为10,那么这个集合的hobby数组索引的条目数量将是普通索引的10倍.

联合数组索引

        联合数组索引就是含有数组字段的联合索引,这种索引不支持一个索引中含有多个数组字段,即一个索引中最多能有一个数组字段,这是为了避免索引条目爆炸式增长,假设一个索引中有两个数组字段,那么这个索引条目的数量将是普通索引的n*m倍

地理空间索引

在原先的users集合上,增加一些地理信息

for(var i = 0;i < 100000;i++){
    db.users.updateOne(
    {username:"user"+i},
    {
        $set:{
            location:{
                type: "Point",
                coordinates: [100+Math.random() * 4,40+Math.random() * 3]
            }
        }
    });
}

创建一个二维空间索引

db.users.createIndex({location:"2dsphere"})
&#39;location_2dsphere&#39;

//查询500米内的人
db.users.find({
  location:{
    $near:{
      $geometry:{type:"Point",coordinates:[102,41.5]},
      $maxDistance:500
    }
  }
})

地理空间索引的type有很多包含Ponit(点) | LineString(线) | Polygon(多边形)

TTL索引

        TTL的全拼是time to live,主要是用于过期数据自动删除,使用这种索引需要在文档中声明一个时间类型的字段,然后为这个字段创建TTL索引的时候还需要设置一个expireAfterSeconds过期时间单位为秒,创建完成后MongoDB会定期对集合中的数据进行检查,当出现:

当前时间TTL索引字段时间>expireAfterSrconds当前时间 - TTL索引字段时间 > expireAfterSrconds

MongoDB将会自动将这些文档删除,这种索引还有以下这些要求:

  • TTL索引只能有一个字段,没有联合TTL索引
  • TTL不能用于固定集合
  • TTL索引是逐个遍历后,发现满足删除条件会使用delete函数删除,效率并不高

首先在我们文档上增减一个时间字段

for(var i = 90000;i < 100000;i++){
    db.users.updateOne(
    {username:"user"+i},
    {
        $set:{
            createdDate:new Date()
        }
    });
}

创建一个TTL索引并且设定过期时间为60s,待过60s后查询,会发现这些数据已经不存在

db.users.createIndex({createdDate:1},{expireAfterSeconds:60})
&#39;createdDate_1&#39;

另外还可以用CollMod命令更改TTL索引的过期时间

db.runCommand({
  collMod:"users",
  index:{
    keyPattern:{createdDate:1},
    expireAfterSeconds:120
  }
})

{ expireAfterSeconds_old: 60, expireAfterSeconds_new: 120, ok: 1 }

条件索引

条件索引也叫部分索引(partial),只对满足条件的数据进行建立索引.

只对50岁以上的user进行建立username_1索引,查看执行计划会发现isPartial这个字段会变成true

db.users.createIndex({username:1},{partialFilterExpression:{
    age:{$gt:50}
  }})
&#39;username_1&#39;

db.users.find({$and:[{username:"user4"},{age:60}]}).explain()
{ 
  queryPlanner: 
  { 
     ......
     winningPlan: 
     { 
        stage: &#39;FETCH&#39;,
        filter: { age: { &#39;$eq&#39;: 60 } },
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { username: 1 },
           indexName: &#39;username_1&#39;,
           ......
           isPartial: true,
           ......
         } 
     },
     rejectedPlans: [] 
  },
  ......
  ok: 1 
}

稀疏索引

        一般的索引会根据某个字段为整个集合创建一个索引,即使某个文档不存这个字段,那么这个索引会把这个文档的这个字段当作null建立在索引当中.

稀疏索引不会对文档中不存在的字段建立索引,如果这个字段存在但是为null时,则会创建索引.

下面给users集合中的部分数据创建稀疏索引

for(var i = 5000;i < 10000;i++){
  if(i < 9000){
    db.users.updateOne(
      {username:"user"+i},
      { $set:{email:(120000000+i)+"@qq.email"}}
    )
  }else{
    db.users.updateOne(
      {username:"user"+i},
      { $set:{email:null}}
    )
  }
}

当不建立索引使用{email:null}条件进行查询时,我们会发现查出来的文档包含没有email字段的文档

db.users.find({email:null})
{ 
  _id: ObjectId("61bdc01ba59136670f6536fd"),
  username: &#39;user0&#39;,
  age: 64.41483801726282,
  sex: 0,
  phone: 18468150001,
  location: 
  { 
    type: &#39;Point&#39;,
    coordinates: [ 101.42490900320335, 42.2576650823515 ] 
  } 
}
......

        然后对email这个字段创建一个稀疏索引使用{email:null}条件进行查询,则发现查询来的文档全部是email字段存在且为null的文档.

db.users.createIndex({email:1},{sparse:true});
&#39;email_1&#39;

db.users.find({email:null}).hint({email:1})
{ 
  _id: ObjectId("61bdc12ca59136670f655a25"),
  username: &#39;user9000&#39;,
  age: 94.18397576757012,
  sex: 0,
  phone: 18468159001,
  hobby: [ &#39;钓鱼&#39;, &#39;乒乓球&#39; ],
  location: 
  { 
    type: &#39;Point&#39;,
    coordinates: [ 101.25903151863596, 41.38450145025062 ] 
  },
  email: null 
}
......

文本索引

文本索引将建立索引的文档字段先进行分词再进行检索,但是目前还不支持中文分词.

下面增加两个文本字段,创建一个联合文本索引

db.blog.insertMany([
  {title:"hello world",content:"mongodb is the best database"},
  {title:"index",content:"efficient data structure"}
])

//创建索引
db.blog.createIndex({title:"text",content:"text"})
&#39;title_text_content_text&#39;
//使用文本索引查询
db.blog.find({$text:{$search:"hello data"}})
{ 
  _id: ObjectId("61c092268c4037d17827d977"),
  title: &#39;index&#39;,
  content: &#39;efficient data structure&#39; 
},
{ 
  _id: ObjectId("61c092268c4037d17827d976"),
  title: &#39;hello world&#39;,
  content: &#39;mongodb is the best database&#39; 
}

唯一索引

        唯一索引就是在建立索引地字段上不能出现重复元素,除了单字段唯一索引还有联合唯一索引以及数组唯一索引(即数组之间不能有元素交集 )

//对title字段创建唯一索引
db.blog.createIndex({title:1},{unique:true})
&#39;title_1&#39;
//插入一个已经存在的title值
db.blog.insertOne({title:"hello world",content:"mongodb is the best database"})
MongoServerError: E11000 duplicate key error collection: mock.blog index: title_1 dup key: { : "hello world" }
//查看一下执行计划,isUnique为true
db.blog.find({"title":"index"}).explain()
{ 
  queryPlanner: 
  { 
     ......
     winningPlan: 
     { 
        stage: &#39;FETCH&#39;,
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { title: 1 },
           indexName: &#39;title_1&#39;,
           isMultiKey: false,
           multiKeyPaths: { title: [] },
           isUnique: true,
           ......
         } 
     },
     rejectedPlans: [] 
  },
  .......
  ok: 1 
}

相关视频教程推荐:《MongoDB教程

以上是带你聊聊MongoDB中丰富的索引类型的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:掘金社区。如有侵权,请联系admin@php.cn删除
MongoDB的目的:灵活的数据存储和管理MongoDB的目的:灵活的数据存储和管理May 09, 2025 am 12:20 AM

MongoDB的灵活性体现在:1)能存储任意结构的数据,2)使用BSON格式,3)支持复杂查询和聚合操作。这种灵活性使其在处理多变数据结构时表现出色,是现代应用开发的强大工具。

MongoDB与Oracle:许可,功能和福利MongoDB与Oracle:许可,功能和福利May 08, 2025 am 12:18 AM

MongoDB适合处理大规模非结构化数据,采用开源许可证;Oracle适合复杂商业事务,采用商业许可证。1.MongoDB提供灵活的文档模型和横向扩展能力,适合大数据处理。2.Oracle提供强大的ACID事务支持和企业级功能,适合复杂分析工作负载。选择时需考虑数据类型、预算和技术资源。

MongoDB与Oracle:探索NOSQL和关系方法MongoDB与Oracle:探索NOSQL和关系方法May 07, 2025 am 12:02 AM

在不同的应用场景下,选择MongoDB还是Oracle取决于具体需求:1)如果需要处理大量非结构化数据且对数据一致性要求不高,选择MongoDB;2)如果需要严格的数据一致性和复杂查询,选择Oracle。

关于MongoDB当前情况的真相关于MongoDB当前情况的真相May 06, 2025 am 12:10 AM

MongoDB当前的表现取决于具体的使用场景和需求。1)在电商平台中,MongoDB适合存储商品信息和用户数据,但处理订单时可能面临一致性问题。2)在内容管理系统中,MongoDB便于存储文章和评论,但处理大量数据时需使用分片技术。

MongoDB与Oracle:文档数据库与关系数据库MongoDB与Oracle:文档数据库与关系数据库May 05, 2025 am 12:04 AM

引言在现代数据管理的世界里,选择合适的数据库系统对于任何项目来说都是至关重要的。我们常常会面临一个选择:是选择MongoDB这种文档型数据库,还是选择Oracle这种关系型数据库?今天我将带你深入探讨MongoDB和Oracle之间的差异,帮助你理解它们的优劣势,并分享我在实际项目中使用它们的经验。本文将会带你从基础知识开始,逐步深入到这两类数据库的核心特性、使用场景和性能表现。无论你是刚入门的数据管理者,还是有经验的数据库管理员,读完这篇文章,你将对如何在项目中选择和使用MongoDB或Ora

MongoDB发生了什么?探索事实MongoDB发生了什么?探索事实May 04, 2025 am 12:15 AM

MongoDB仍然是一个强大的数据库解决方案。 1)它以灵活性和可扩展性着称,适合存储复杂数据结构。 2)通过合理索引和查询优化,可以提升其性能。 3)使用聚合框架和分片技术,可以进一步优化和扩展MongoDB的应用。

Mongodb注定要失败吗?消除神话Mongodb注定要失败吗?消除神话May 03, 2025 am 12:06 AM

MongoDB并未注定要没落。1)其优势在于灵活性和可扩展性,适合处理复杂数据结构和大规模数据。2)劣势包括高内存使用和较晚引入的ACID事务支持。3)尽管存在性能和事务支持的质疑,但MongoDB通过技术改进和市场需求的推动,仍然是一个强大的数据库解决方案。

MongoDB的未来:看看它的前景MongoDB的未来:看看它的前景May 02, 2025 am 12:08 AM

mongodb'sfutureispromisingwithgrowthincloudstegration,Real-TimedataProcessing,andai/mlapplications,tryitfaceschallengesincompetition,performance,performance,security andeaseofuse.1)

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具