索引是特殊的数据结构,它以易于遍历的形式存储部分集合数据集。索引存储特定字段或字段集的值,按字段值排序。
MongoDB的索引几乎与传统的关系型数据库索引一模一样,它的主键_id
也是一个索引,MongoDB的数据按照_id
的顺序存储在内存页与磁盘块上。但是,_id
与业务毫无关联,在业务相关的条件查询时,还是需要进行全表扫描才能找到对应页,效率并不高。
- 为了避免性能瓶颈,可以根据常用的查询建立索引
- 索引的值是按照一定的顺序排列的,使用索引键对文档进行排序效率非常高,只需要按照索引读取数据即可。
不过,使用索引也是有代价的,不仅会增加磁盘与内存的消耗,对于添加的每一个索引,每次写操作(插入、更新、删除)都会耗费更多时间,这是因为,数据发生变动时,还需要额外的开销更新索引。
文章目录
聚簇索引与非聚簇索引
磁盘上的数据某一时刻只能有一种排序方式,而聚簇索引的特点是:索引顺序与数据存储顺序一致,所以聚簇索引只能有一个。
《数据库原理》中对聚簇索引的定义:聚簇索引的叶子节点是数据节点,非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针。
所以Mysql的InnoDB引擎的主键索引是聚簇索引、MyIsam引擎使用的是非聚簇索引。
MongoDB不会将_id
索引与文档内容放在一起,所以MongoDB的_id
索引不是聚簇索引,mogoDB将数据与索引分开存放,通过RecordId间接引用。假设为字段”name“
创建了索引,主键id
为主键索引,那么该集合就通过索引查找RecordId,再查找数据。
MongoDB索引分类
主键索引
_id
索引是默认的主键索引,与业务相关联的项不适合用作主键(难以保障全局唯一、非null),建议使用_id
作为主键。
单字段索引
对单个filed建立索引,也是常说的“普通索引”;建立索引时可以指定索引数据的order:正序还是倒序。MongoDB 3.0后的版本,使用createIndex
、ensureIndex
是一样的,均是创建索引的命令。
db.mycollection.ensureIndex({
"name":1}) //对score字段建立索引、1表示正序、-1表示倒序
db.mycollection.createIndex({
"name":1}) // MongoDB 3.0后的版本,可以使用createIndex
复合索引
两个或两个以上的键建立索引,可以减小检索的范围。复合索引与Mysql一样,也是按照左侧匹配规则。例如:对于集合col
中的字段age
和name
建立复合索引:
db.col.ensureIndex({
"age":1,"name":1});
1表示按照正序排列,-1表示按照倒序排列,若插入4条数据,
1 db.col.insert({
age:20,name:'a1'})
2 db.col.insert({
age:21,name:'a2'})
3 db.col.insert({
age:19,name:'a3'})
4 db.col.insert({
age:21,name:'a4'})
MongoDB在复合索引中存储这些数据的顺序是:(19,a3)、(20,a1)、(21,a2)、(21,a4)
。编写查询语句时应该先匹配age
,再匹配name
。
复合索引与排序共用
复合索引与排序共用的场景很常见,使用不当会导致内存排序,默认的快速排序的时间复杂度是NlogN
,在集合文档数超过一定量级后,耗时就会很大。所以要选择最佳的索引创建方式,尽量避免内存排序。
内存排序的产生:
创建两个复合索引,唯一区别就是键顺序不同,排序规则都是正序。
db.col.