MongoDB索引Index
什么是索引
索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。索引目标是提高数据库的查询效率,没有索引的话,查询会进行全表扫描(scan every document in a collection),数据量大时严重降低了查询效率。默认情况下Mongo在一个集合(collection)创建时,自动地对集合的_id创建了唯一索引
索引类型
3.2.1 单键索引 (Single Field)
MongoDB支持所有数据类型中的单个字段索引,并且可以在文档的任何字段上定义。
对于单个字段索引,索引键的排序顺序无关紧要,因为MongoDB可以在任一方向读取索引。
单个例上创建索引:
db.集合名.createIndex({"字段名":排序方式})
特殊的单键索引 过期索引 TTL ( Time To Live)
TTL索引是MongoDB中一种特殊的索引, 可以支持文档在一定时间之后自动过期删除,目前TTL索引只能在单字段上建立,并且字段类型必须是日期类型。
db.集合名.createIndex({"日期字段":排序方式}, {expireAfterSeconds: 秒数})
复合索引(Compound Index)
通常我们需要在多个字段的基础上搜索表/集合,这是非常频繁的。 如果是这种情况,我们可能会考虑在MongoDB中制作复合索引。 复合索引支持基于多个字段的索引,这扩展了索引的概念并将它们扩展到索引中的更大域。
制作复合索引时要注意的重要事项包括:字段顺序与索引方向
db.集合名.createIndex( { "字段名1" : 排序方式, "字段名2" : 排序方式 } )
多键索引(Multikey indexes)
针对属性包含数组数据的情况,MongoDB支持针对数组中每一个element创建索引,Multikeyindexes支持strings,numbers和nested documents
地理空间索引(Geospatial Index)
针对地理空间坐标数据创建索引。
2dsphere索引,用于存储和查找球面上的点
2d索引,用于存储和查找平面上的点
db.company.insert(
{
loc : { type: "Point", coordinates: [ 116.482451, 39.914176 ] },
name: "大望路地铁",
category : "Parks"
}
) d
b.company.ensureIndex( { loc : "2dsphere" } )
参数不是1或-1,为2dsphere 或者 2d。还可以建立组合索引。
db.company.find({
"loc" : {
"$geoWithin" : {
"$center":[[116.482451,39.914176],0.05]
}
}
})
全文索引
MongoDB提供了针对string内容的文本查询,Text Index支持任意属性值为string或string数组元素的
索引查询。注意:一个集合仅支持最多一个Text Index,中文分词不理想 推荐ES
db.集合.createIndex({"字段": "text"})
db.集合.find({"$text": {"$search": "coffee"}})
哈希索引 Hashed Index
针对属性的哈希值进行索引查询,当要使用Hashed index时,MongoDB能够自动的计算hash值,无
需程序计算hash值。注:hash index仅支持等于查询,不支持范围查询
db.集合.createIndex({"字段": "hashed"})
索引和explain 分析
索引管理
创建索引并在后台运行
db.COLLECTION_NAME.createIndex({"字段":排序方式}, {background: true});
获取针对某个集合的索引
db.COLLECTION_NAME.getIndexes()
索引的大小
db.COLLECTION_NAME.totalIndexSize()
索引的重建
db.COLLECTION_NAME.reIndex()
索引的删除
db.COLLECTION_NAME.dropIndex("INDEX-NAME")
db.COLLECTION_NAME.dropIndexes()
注意: _id 对应的索引是删除不了的
explain 分析
使用js循环 插入100万条数据 不使用索引字段 查询查看执行计划 ,然后给某个字段建立索引,使用索引字段作为查询条件 再查看执行计划进行分析
explain()也接收不同的参数,通过设置不同参数我们可以查看更详细的查询计划。
queryPlanner:queryPlanner是默认参数,具体执行计划信息参考下面的表格。
executionStats:executionStats会返回执行计划的一些统计信息(有些版本中和allPlansExecution等同)。
allPlansExecution:allPlansExecution用来获取所有执行计划,结果参数基本与上文相同。
queryPlanner 默认参数
executionStats参数
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+IDHACK
Fetch+IXSCAN
Limit+(Fetch+IXSCAN)
PROJECTION+IXSCAN
SHARDING_FITER+IXSCAN
不希望看到包含如下的stage:
COLLSCAN(全表扫描)
SORT(使用sort但是无index)
COUNT 不使用index进行count)
allPlansExecution参数
queryPlanner 参数和executionStats的拼接
慢查询分析
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结果 确定是否缺少索引
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+树更适合外部存储,也就是磁盘存储,使用-结构的话,每次磁盘预读中的很多数据是用不上的数据。因此,它没能利用好磁盘预读的提供的数据。由于节点内无 data 域,每个节点能索引的范围更大更精确。
(3)注意这个区别相当重要,是基于(1)(2)的,B-树每个节点即保存数据又保存索引 树的深度小,所以磁盘IO的次数很少,B+树只有叶子节点保存,较B树而言深度大磁盘IO多,但是区间访问比较好。
下一篇: java与设计模式(四)-工厂方法模式