MongoDB 索引机制

转载用于收藏学习,尊重原创

原文链接

https://blog.csdn.net/July_whj/article/details/124087435

————————————————
版权声明:本文为CSDN博主「July_whj」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/July_whj/article/details/124087435

一、相关术语

1.1、Index/Key/DataPage

索引、键、数据页分别是什么?

什么是索引

Covered Query,覆盖查询

如果所有需要的字段都在索引中,不需要额外的字段,就可以不再需要从数据页加载数据,这就是查询覆盖。

db.human.createIndex({firstName: 1, lastName: 1, gender: 1, age: 1})

IXSCAN/COLLSCAN

索引扫描/集合扫描(全表扫描)

Query Shape

查询形态,即查询条件:不同的查询条件对索引的影响是不同的,比如等值查询和范围查询。

Index Prefix

索引前缀:

db.human.createIndex({firstName: 1, lastName: 1, gender: 1, age: 1})

以上索引的全部前缀包括:


   
   
  1.  {firstName:  1}
  2.  {firstName:  1, lastName:  1}
  3.  {firstName:  1, lastName:  1, gender:  1}

所有索引前缀都可以被该索引覆盖,没有必要针对这些查询建立额外的索引;

Selectivity

过滤性:

在一个有10000条记录的集合中:

  • 满足 gender= F 的记录有4000 条
  • 满足 city=LA 的记录有 100 条
  • 满足 ln=‘parker’ 的记录有 10 条

条件 ln 能过滤掉最多的数据,city 其次,gender 最弱。所以 ln 的过 滤性(selectivity)大于 city 大于 gender。

二、B树结构

索引背后是 B-树。要正确使用索引,必须先了解 B-树的工作原理。

B- 树: 基于B树,但是子节点数量可以超过2个。

由于 B树/B-树的工作过程过于复杂,但本质上它是一个有序的数据结构。我们用数组来理解它。假设索引为{a: 1}(a 升序):

三、索引执行计划

 

假设集合有两个索引

  • {city: 1}

  • {last_name:1 }

查询:

db.members.find({ city: “LA”, last_name: “parker”})

问题:用哪个索引?

两个线程同时尝试两个索引看哪个索引跑的比较快就选谁。

3.1、explain()


   
   
  1. -- 写入10000条文档
  2. for (var i= 1;i< 100000; i++) 
  3.     db.col. insert({name:i, age:i,
  4.      date:new Date() } 
  5. )
  6. -- 查询
  7. db.col. find({name: 1111}).explain( true)

查看执行计划:


   
   
  1. "executionStats" : 
  2. "executionSuccess" :  true,
  3.      "nReturned" :  1//返回数据条数
  4.      "executionTimeMillis" :  58//执行时间
  5.      "totalKeysExamined" :  0//使用索引数
  6.      "totalDocsExamined" :  99999,   //扫描文档数
  7.      "executionStages" : {
  8.      "stage" :  "COLLSCAN",
  9.      "filter" : { "name" : { "$eq" :  1111}}, 
  10.      "nReturned" :  1
  11.      "executionTimeMillisEstimate" :  53,
  12.      "works" :  100001,
  13.      "advanced" :  1,
  14.      "needTime" :  99999,
  15.      "needYield" :  0,
  16.      "saveState" :  783,
  17.      "restoreState" :  783,
  18.      "isEOF" :  1,
  19.      "invalidates" :  0,
  20.      "direction" :  "forward",
  21.      "docsExamined" :  99999
  • 创建name索引

db.col.createIndex({name:1})

在查看执行计划:


   
   
  1. "executionStats" : {
  2.    "executionSuccess" :  true,
  3.    "nReturned" :  1//返回数据条数
  4.    "executionTimeMillis" :  3//执行时间
  5.    "totalKeysExamined" :  1//使用索引数
  6.    "totalDocsExamined" :  1//扫描数据条数
  7.    "executionStages" : {
  8.    "stage" :  "FETCH",
  9.    "nReturned" :  1,
  10.    "executionTimeMillisEstimate" :  0,
  11.    "docsExamined" :  1"alreadyHasObj" :  0,
  12.    "inputStage" : {
  13.    "stage" :  "IXSCAN",
  14.    "nReturned" :  1,
  15.    "executionTimeMillisEstimate" :  0,
  16.    "works" :  2,
  17.    "advanced" :  1,
  18. … }

我们可以看到,使用索引后,性能极大的提升。

四、MongoDB 索引类型

  • 单键索引
  • 组合索引
  • 多值索引
  • 地理位置索引
  • 全文索引
  • TTL索引
  • 部分索引
  • 哈希索引

4.1、组合索引 – Compound Index

db.members.find({ gender: “F”, age: {$gte: 18}}).sort(“join_date:1”)


   
   
  1. { gender:  1, age:  1, join_date:  1 }
  2. { gender:  1, join_date: 1, age:  1 }
  3. { join_date:  1, gender:  1, age:  1 }
  4. { join_date:  1, age:  1, gender:  1 }
  5. { age:  1, join_date:  1, gender:  1}
  6. { age:  1, gender:  1, join_date:  1}
  7. 这么多候选的,用哪一个?

组合索引的最佳方式:ESR原则

  • 精确(Equal)匹配的字段放最前面
  • 排序(Sort)条件放中间
  • 范围(Range)匹配的字段放最后面

同样适用: ES, ER;

4.1.1、组合索引工作模式: 精确匹配

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

我们查询:


   
   
  1. db .test .find({
  2.    a2
  3.   b:  2
  4.   c:  1
  5. })

4.1.2、组合索引工作模式: 范围查询

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

我们查询:


   
   
  1. db.test.find({
  2.    a:  2
  3.    b: { $gte2$lte3}, 
  4.    c:  1
  5. })    

范围组合查询: 索引字段顺序的影响:

这里我们应该遵循ESR原则,先进行等值字段创建索引。在进行范围字段索引创建。

范围+排序组合查询: 索引字段顺序的影响

这里ERS方式使用了内存排序,而内存排序是非常消耗性能的,需要将数据从磁盘加载到内存中,在内存中进行排序操作。而将字段C放在第二位,B-树本身已经对C进行了排序,可以直接查询使用。

4.2、地理位置索引

创建索引:


   
   
  1. db .geo_col .createIndex
  2.         { location: “ 2d”} , 
  3.         { min:- 20, max:  20 , bits:  10},
  4.         {collation:
  5.             {locale:  "simple"
  6.         } 
  7. )

查询:


   
   
  1. db.geo_col.find( 
  2.   { location : 
  3.   {  $geoWithin : 
  4.   {  $box : [ [  11 ] , [  33 ] ] } } }
  5. )

4.3、全文索引

全文索引可以对某些字段创建索引,在查询时,可以自动检索增加字段的索引信息。


   
   
  1. db.<collection_name>.insert(
  2. { _ id1, content: “This morning I had a cup of 
  3. coffee.”, about: “beverage”, keywords: [ 
  4. “coffee” ] } ,
  5. { _ id2, content:  "Who doesn't like cake?"
  6. about:  "food", keywords: [  "cake""food"
  7. "dessert" ] },
  8. { _ id3, content:  "Why need coffee?", about: 
  9. ”food ", keywords: [ ”drink""food" ] }
  10. )

创建索引:


   
   
  1. db.<collection_name> .createIndex(
  2.     {‘ content’ :  "text" } 
  3. )

查询:


   
   
  1. db.<collection_name>.find(
  2. $text : 
  3.     {  $search :  "cup coffee like" }
  4. } ) 
  5. db.<collection_name>.find(
  6. $text : 
  7. $search :  "a cup of coffee" }
  8. } )

我们可以直接使用"test"进行查询操作,如果在创建索引时,增加了content、about、keywords,则分别会在这三个字段中查询。

排序操作:


   
   
  1. db.<collection_name>.find( 
  2. $text : {  $search : ”coffee "} },
  3. { textScore: { $meta : "textScore " }} 
  4. ).sort({ textScore: { $meta: "textScore " }} )

4.4、部分索引

创建部分索引:


   
   
  1. db. <collection_name>.createIndex( 
  2.     {‘a’: 1 }, 
  3.     { partialFilterExpression: 
  4.     {a:
  5.         {$gte:5}
  6.     }
  7. )

创建 部分索引可以针对部分数据进行索引创建,如a大于5的数据进行索引创建。

现实场景中:如统计今年订单量,那么去年订单就可以不创建索引,可以节省深大的存储空间。

4.5、其他索引技巧

  • 后台创建索引
  • db.member.createIndex( { city: 1}, {background: true} )

使用background:true进行后台索引创建,创建索引是比较耗时操作。

  • 对BI / 报表专用节点单独创建索引
  • 该从节点priority设为0
  • 关闭该从节点
  • 以单机模式启动
  • 添加索引(分析用)
  • 关闭该从节点,以副本集模式启动
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值