MongoDB索引类型(单键、复合、多键、地理空间索引、全文索引、哈希索引)、explain索引分析以及应用场景有哪些

一、索引类型

1、单键索引(Single Field)

MongoDB支持所有数据类型中的单个字段索引,并且可以在文档的任何字段上定义。
对于单个字段索引,索引键的排序顺序无关紧要,因为MongoDB可以在任一方向读取索引。
单个实例上创建索引:
db.集合名.createIndex({“字段名”:排序方式})

特殊的单键索引 过期索引 TTL ( Time To Live)
TTL索引是MongoDB中一种特殊的索引, 可以支持文档在一定时间之后自动过期删除,目前TTL索引只能在单字段上建立,并且字段类型必须是日期类型

db.集合名.createIndex({"日期字段":排序方式}, {expireAfterSeconds: 秒数})

2、复合索引(Compound Index)

我们需要在多个字段的基础上搜索表/集合,这是非常频繁的。 如果是这种情况,我们可能会考虑在MongoDB中制作复合索引。 复合索引支持基于多个字段的索引,这扩展了索引的概念并将它们扩展到索引中的更大域。

制作复合索引时要注意的重要事项包括:字段顺序与索引方向

db.集合名.createIndex( { "字段名1" : 排序方式, "字段名2" : 排序方式 } )

3、多键索引(Multikey indexes)

针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引,Multikey indexes支持strings,numbers和nested documents

4、地理空间索引(Geospatial Index)

针对地理空间坐标数据创建索引。
2dsphere索引,用于存储和查找球面上的点
2d索引,用于存储和查找平面上的点

db.company.insert(
	{
		loc : { type: "Point", coordinates: [ 116.482451, 39.914176 ] },
		name: "大望路地铁",
		category : "Parks"
	}
) 
db.company.ensureIndex( { loc : "2dsphere" } )
# 参数不是1或-1,为2dsphere 或者 2d。还可以建立组合索引。
db.company.find({
	"loc" : {
		"$geoWithin" : {
		"$center":[[116.482451,39.914176],0.05]
		}
	}
})

5、全文索引

MongoDB提供了针对string内容的文本查询,Text Index支持任意属性值为string或string数组元素的索引查询。注意:一个集合仅支持最多一个Text Index,中文分词不理想 推荐ES。

db.集合.createIndex({"字段": "text"})
db.集合.find({"$text": {"$search": "coffee"}})

6、哈希索引 (Hashed Index)

针对属性的哈希值进行索引查询,当要使用Hashed index时,MongoDB能够自动的计算hash值,无需程序计算hash值。注:hash index仅支持等于查询,不支持范围查询。

db.集合.createIndex({"字段": "hashed"})

二、索引和explain分析

1、索引管理

  1. 创建索引并在后台运行

     db.COLLECTION_NAME.createIndex({"字段":排序方式}, {background: true});
    
  2. 获取针对某个集合的索引

     db.COLLECTION_NAME.getIndexes()	
    
  3. 索引的大小

     db.COLLECTION_NAME.totalIndexSize()
    
  4. 索引的重建

     db.COLLECTION_NAME.reIndex()
    
  5. 索引的删除

     db.COLLECTION_NAME.dropIndex("INDEX-NAME")
     db.COLLECTION_NAME.dropIndexes()
     注意: _id 对应的索引是删除不了的
    

2、explain分析

使用js循环 插入100万条数据 不使用索引字段 查询查看执行计划 ,然后给某个字段建立索引,使用索引字段作为查询条件 再查看执行计划进行分析

explain()也接收不同的参数,通过设置不同参数我们可以查看更详细的查询计划。

  • queryPlanner:queryPlanner是默认参数,具体执行计划信息参考下面的表格。
  • executionStats:executionStats会返回执行计划的一些统计信息(有些版本中和allPlansExecution等同)。
  • allPlansExecution:allPlansExecution用来获取所有执行计划,结果参数基本与上文相同
  1. queryPlanner 默认参数

在这里插入图片描述

  1. executionStats参数
    在这里插入图片描述

  2. executionStats返回逐层分析
    第一层,executionTimeMillis最为直观explain返回值是executionTimeMillis值,指的是这条语句的执行时间,这个值当然是希望越少越好。
    其中有3个executionTimeMillis,分别是:
    executionStats.executionTimeMillis 该query的整体查询时间。
    executionStats.executionStages.executionTimeMillisEstimate 该查询检索document获得数据的时间。
    executionStats.executionStages.inputStage.executionTimeMillisEstimate 该查询扫描文档 index所用时间。
    第二层,index与document扫描数与查询返回条目数 这个主要讨论3个返回项 nReturned、
    totalKeysExamined、totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目、文档扫描条目。 这些都是直观地影响到executionTimeMillis,我们需要扫描的越少速度越快。 对于一个查询,
    我们最理想的状态是:nReturned=totalKeysExamined=totalDocsExamined
    第三层,stage状态分析 那么又是什么影响到了totalKeysExamined和totalDocsExamined?是stage的类型。
    类型列举如下:
    COLLSCAN:全表扫描
    IXSCAN:索引扫描
    FETCH:根据索引去检索指定document
    SHARD_MERGE:将各个分片返回数据进行merge
    SORT:表明在内存中进行了排序
    LIMIT:使用limit限制返回数
    SKIP:使用skip进行跳过
    IDHACK:针对_id进行查询
    SHARDING_FILTER:通过mongos对分片数据进行查询
    COUNT:利用db.coll.explain().count()之类进行count运算
    TEXT:使用全文索引进行查询时候的stage返回
    PROJECTION:限定返回字段时候stage的返回

    对于普通查询,我希望看到stage的组合(查询的时候尽可能用上索引):
    Fetch+IDHACKFetch+IXSCAN
    Limit+(Fetch+IXSCAN)
    PROJECTION+IXSCAN
    SHARDING_FITER+IXSCAN
    不希望看到包含如下的stage:
    COLLSCAN(全表扫描)
    SORT(使用sort但是无index)
    COUNT 不使用index进行count)

  3. allPlansExecution参数

     queryPlanner 参数和executionStats的拼接
    

用法:

db.resumer.find({'date':{$gte:ISODate("2022-03-10T06:47:57Z")}}).limit(30).explain("allPlansExecution")

3、慢查询分析

  1. 开启内置的查询分析器,记录读写操作效率
    db.setProfilingLevel(n,m),n的取值可选0,1,2
    0表示不记录
    1表示记录慢速操作,如果值为1,m必须赋值单位为ms,用于定义慢速查询 时间的阈值
    2表示记录所有的读写操作
  2. 查询监控结果
    db.system.profile.find().sort({millis:-1}).limit(3)
  3. 分析慢速查询
    应用程序设计不合理、不正确的数据模型、硬件配置问题,缺少索引等
  4. 解读explain结果 确定是否缺少索引

4、MongoDB 索引底层实现原理分析

MongoDB 是文档型的数据库,它使用BSON 格式保存数据,比关系型数据库存储更方便。比如之前关系型数据库中处理用户、订单等数据要建立对应的表,还要建立它们之间的关联关系。但是BSON就不一样了,我们可以把一条数据和这条数据对应的数据都存入一个BSON对象中,这种形式更简单,通俗易懂。MySql是关系型数据库,数据的关联性是非常强的,区间访问是常见的一种情况,底层索引组织数据使用B+树,B+树由于数据全部存储在叶子节点,并且通过指针串在一起,这样就很容易的进行区间
遍历甚至全部遍历。MongoDB使用B-树,所有节点都有Data域,只要找到指定索引就可以进行访问,
单次查询从结构上来看要快于MySql。

B-树是一种自平衡的搜索树,形式很简单:
在这里插入图片描述

B-树的特点:
(1) 多路 非二叉树
(2) 每个节点 既保存数据 又保存索引
(3) 搜索时 相当于二分查找

B+树是B-树的变种
在这里插入图片描述

B+ 树的特点:
(1) 多路非二叉
(2) 只有叶子节点保存数据
(3) 搜索时 也相当于二分查找
(4) 增加了 相邻节点指针

从上面我们可以看出最核心的区别主要有俩,一个是数据的保存位置,一个是相邻节点的指向。就是这俩造成了MongoDB和MySql的差别。
(1)B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和data 在一起 适合随机读写 ,而区间查找效率很差。
(2)B+树更适合外部存储,也就是磁盘存储,使用B-结构的话,每次磁盘预读中的很多数据是用不上的数据。因此,它没能利用好磁盘预读的提供的数据。由于节点内无 data 域,每个节点能索引的范围
更大更精确。
(3)注意这个区别相当重要,是基于(1)(2)的,B-树每个节点即保存数据又保存索引 树的深度小,所以磁盘IO的次数很少,B+树只有叶子节点保存,较B树而言深度大磁盘IO多,但是区间访问比较好。

三、MongoDB的应用场景

1、适用场景

  • 网站数据:Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
  • 缓存:由于性能很高,Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源过载。
  • 大尺寸、低价值的数据:使用传统的关系型数据库存储一些大尺寸低价值数据时会比较浪费,在此之前,很多时候程序员往往会选择传统的文件进行存储。
  • 高伸缩性的场景:Mongo 非常适合由数十或数百台服务器组成的数据库,Mongo 的路线图中已经包含对MapReduce 引擎的内置支持以及集群高可用的解决方案。
  • 用于对象及JSON 数据的存储:Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。

2、行业应用场景

  • 游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新。
  • 物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
  • 社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。
  • 物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析。
  • 直播,使用 MongoDB 存储用户信息、礼物信息等。

3、是否选中MongoDB

在这里插入图片描述

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值