Mongodb 索引 对查询结果的排序

本文主要讨论 “mongodb的索引” 和 “查询结果的排序” 之间的关系,索引对排序有什么影响,为什么有影响,应该遵循什么规则。

 

1. 先从创建单字段索引,认识“索引排序”:

db.集合名.createIndex(要给哪一列创建索引 [,额外选项]);

  第1个参数是 “给哪一列创建索引”,它的格式是: {key:1或-1},其中1表示升序,-1表示降序。

  第2个参数是 “额外选项”,它是可选的,比如:设置索引名称、指定索引类型等等。

  举例: db.集合名.createIndex({age:1}) ;  —> 表示在age字段上创建索引并按照升序的方式存储索引数据。

  注意:索引也是一堆数据,索引是一些按照指定规则排序的数据, 最终也是被存储起来的, 也是占用磁盘空间的。

            所以,在创建索引的时候要指定一个存储顺序(1升序, -1降序) ,告诉它是升序存储还是降序存储。

 

2. 给索引数据排序,意义何在 ?

     在MongoDB中,排序操作,可以通过从索引中按照索引的顺序获取文档的方式,来保证结果的有序性。

     如果MongoDB的查询计划器(planner) 没法从索引中得到排序顺序,那么它就需要在内存中对结果排序。

     相比于“不用索引的排序”操作,用索引会有更好的性能。

     注意,关键是:不用索引的排序操作,会在用了超过32MB内存时终止,也就是说MongoDB只能支持32MB的非索引排序 。

     如果数据量很大,比如我目前的应用场景下,都是千万级数据量,而且飞速增加,达亿级…… 

 

3. 用索引对查询结果进行排序

    索引,是以升序(1) 或 降序(-1) 的排序顺序,存储对字段的引用。 

    单字段索引的排序

    如果在单字段上是升序索引或降序索引,则对该字段的排序操作可以是任一方向。

     例如:在集合records的a字段上创建一个升序索引:db.records.createIndex( { a: 1 } ) ; 

                上面的索引可以支持在 a 字段上的升序排序:db.records.find().sort( { a: 1 } ) ;   

                上面是索引还可以通过按相反的顺序遍历索引,来支持在 a 字段上的降序排序:db.records.find().sort( { a: -1 } ) ; 

    对于单字段索引,字段的排序顺序并不重要,因为MongoDB可以在任意方向遍历索引。

    但是,对于复合索引,排序顺序在确定索引是否支持排序操作时很重要。

    复合索引的排序

    你可以指定在索引的所有字段或者部分字段上排序。

    用复合索引排序时,sort() 中所指定的排序字段有以下两点需要遵循,否则不会走索引排序:

    (1)排序字段的 “排列顺序”,必须和它们在索引中的排列顺序一致。

             划重点:前后顺序,必须一致。

             例如,索引 { a: 1, b: 1 } ,可以支持 { a: 1, b: 1 } 上的排序,但不支持 { b: 1, a: 1 } 上的排序。

    (2)排序字段的 “排序顺序”,必须和索引中的对应字段的排序顺序完全相同完全相反

             划重点:升降序顺序,要么完全一样、要么完全相反。

             例如,索引 { a: 1, b: -1 } ,可以支持 { a: 1, b: -1 }  和  { a: -1, b: 1 }  的排序,但不支持 { a: -1, b: -1 } 或 { a: 1, b: 1 } 的排序。 

 

     实例:events集合中包含username和date字段,建立复合索引 db.events.createIndex( { "username" : 1, "date" : -1 } ) ,它可以支持下面两种排序操作: 

               db.events.find().sort( { username: 1, date: -1 } )  先按username升序再按date降序,它和索引字段的升降序顺序完全一样

               db.events.find().sort( { username: -1, date: 1 } )  先按username降序再按date升序,它和索引字段的升降序顺序完全相反

              上面的索引不支持 db.events.find().sort( { username: 1, date: 1 } )  先按username升序再按date升序的排序,因为它和索引字段的升降序顺序 既不完全一样、也不完全相反

 

4. 排序与索引前缀

     如果“排序字段”能和“索引字段或索引前缀”对应起来,那MongoDB就可以使用索引来对查询结果进行排序。

     复合索引的前缀是指被索引字段的子集,它由一个或多个排在最开始的字段组成。

     例如,在集合 data 上创建一个复合索引:db.data.createIndex( { a:1, b: 1, c: 1, d: 1 } )  那么这个索引的前缀如下:

               { a: 1 }

               { a: 1, b: 1 }

               { a: 1, b: 1, c: 1 }

              下面的查询和排序操作,都可以使用索引前缀来排序查询结果。

              也就是说下面这些操作都不需要在内存中对结果集排序。

例子

索引前缀

db.data.find().sort( { a: 1 } ) { a: 1 }
db.data.find().sort( { a: -1 } ) { a: 1 }
db.data.find().sort( { a: 1, b: 1 } ) { a: 1, b: 1 }
db.data.find().sort( { a: -1, b: -1 } ) { a: 1, b: 1 }
db.data.find().sort( { a: 1, b: 1, c: 1 } ) { a: 1, b: 1, c: 1 }
db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } ) { a: 1, b: 1 }

    索引也支持使用非前缀字段来排序。

    不过这种情况是有前提的,就是:查询语句中 必须 把排序字段之前的所有前缀字段,都加上相等条件。

     例如,集合 data 有 { a: 1, b: 1, c: 1, d: 1 } 索引,如下操作可以使用索引来排序:

例子

索引前缀

db.data.find( { a: 5 } ).sort( { b: 1, c: 1 } ) { a: 1 , b: 1, c: 1 }
db.data.find( { b: 3, a: 4 } ).sort( { c: 1 } ) { a: 1, b: 1, c: 1 }
db.data.find( { a: 5, b: { $lt: 3} } ).sort( { b: 1 } ) { a: 1, b: 1 }

     如最后一个操作所示,只有索引中那些排列在排序字段前面的字段,必须在查询语句中有相等匹配条件,其他的索引字段才可以指定其他匹配条件。

     如果查询语句 没有 对排列在排序字段前面 或 与之有所重叠的前缀字段指定相等匹配条件,那么操作将 不会 走索引。

     例如,如下操作指定了排序 { c: 1 } ,但是查询语句并没有对前缀字段 a 和 b 指定相等匹配:

                db.data.find( { a: { $gt: 2 } } ).sort( { c: 1 } ) ;

               db.data.find( { c: 5 } ).sort( { c: 1 } ) ; 

              这些操作不会走索引 { a: 1, b: 1, c: 1, d: 1 } ,甚至可能不用索引检索文档。

 

 

你可能感兴趣的:(mongodb,mongodb,索引,数据库)