MongoDB索引使用总结
背景MongoDB 是目前最流行的文档型数据库。MongoDB 的采用类 json 的存储格式对开发者来说非常友好。本文梳理了 MongoDB 索引的底层结构以及使用经验,不足之处欢迎大家指正。
MongoDB 提供范围广泛的索引类型和功能以及特定于语言的排序顺序,以支持对数据的复杂访问模式。 MongoDB 索引可以按需创建和删除来适应不断变化的应用程序需求和查询模式,并且可以在文档中的任何字段上声明,包括嵌套在数组中的字段。本文介绍一下 MongoDB 中的索引底层结构、索引遍历过程、建索引以及如何使用。
基本使用
分类
MongoDB 中的索引与其他数据库系统中的索引类似。 MongoDB 在集合级别定义索引,并支持 MongoDB 集合中文档的任何字段或子字段的索引。 常见的有以下类型: 键索引、复合索引、多键索引、地理空间索引、全文本索引和哈希索引。
创建/删除/隐藏
语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。`db.col.createIndex({"a":1})`
createIndex 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。db.col.createIndex({"a":1,"b":-1})
删除索引在底层直接删除文件,然后修改元数据
在删除索引前,可以先隐藏索引,查看集群是否异常后,才真正删除索引, 可有效帮助业务判断索引是否可以删除。
底层文件存储
MongoDB 底层是如何存储数据的,一个 collection 一个文件吗?索引在底层是如何组织的? 一个 collection 对应到底层存储引擎就是一个文件,另外每个索引也是单独的文件,每个数据和索引文件的默认结构是 b 树,用户建表的时候也可以指定 lsm 结构,不过绝大多数用户基本都是使用 b 树结构,本文的讨论主要围绕 b 树这种结构来进行。
比如用户建一个普通的表,默认会带一个_id 索引,会产生俩个文件,一个文件存放数据,一个存放_id 索引,这俩个文件通过 RecordId 来连接,用户每插入一条数据,mongo 会生成一条与之对应的自增的 RecordId, 不过用户不感知,RecordId 是与 MySQL 中的自增主键类似。数据文件是 RecordId 到数据的映射, _id 索引文件是_id 到 RecordId 的映射,如果通过指定_id 查询,会现在_id 索引文件中找到 RecordId, 然后再到数据文件中查询数据,如果用户再新建索引,那么在 wt 就会再新建一个文件,同样按 b 树组织,该文件记录了索引到 RecordId 的映射,用户使用索引查询时,同样的如同_id 索引,先找到 RecordId, 然后再到数据文件中查询数据。
可以通过以下方式查找数据对应的RecordId PRIMARY> db.coll.find.showRecordId { "_id" : ObjectId("647861f72b531acaacf4afb2"), "a" : 1, "b" : 1, "$recordId" : NumberLong(1) } { "_id" : ObjectId("647861fa2b531acaacf4afb3"), "a" : 1, "b" : 2, "$recordId" : NumberLong(2) }
底层格式存储
在 MongoDB 的 Schema-free 架构下,索引字段可以存储不同类型的值,在索引 b 树中,有个基本的问题,实现不同类型的比较呢? MongoDB 通过 BSON 结构来存储数据,具体结构的解析可见BSON 结构解析 ,并且规定了不同类型之间的大小关系。
1. MinKey (internal type) 2. Null 3. Numbers (ints, longs, doubles, decimals) 4. Symbol, String 5. Object 6. Array 7. BinData 8. ObjectId 9. Boolean 10. Date 11. Timestamp 12. Regular Expression 13. MaxKey (internal type)
在这个限制下, 就只需要对比同种类型的大小了,BSON 的基本比较流程如下:先比较类型,如果类型一样才使用 BSONElement::compareElements 比较值。
但是对于索引如果直接使用上述方法去做大小比较,具有以下的俩个缺点: