Mongodb索引探索(一)

索引是数据库中的一个重要对象,主要用于支持高效查询操作。如果没有索引,数据库就只能进行全表扫描,效率将极为低下。mongodb的索引体系比较庞大,按照索引类型,我准备分这么几个部分来进行阐述:

  • 基本索引

  • Text索引

  • GEO索引

概述

本文将简单介绍常用的基本索引类型,已经索引的相关操作。根据官方的文档,Mongodb有这么几种常见索引:

  • Default _id 主键索引,默认作用在_id

  • Single Field 单键索引,针对单个field的索引

  • Compound 复合索引,针对多个field的索引

  • Multikey Index,这个我都不知道怎么翻,多键索引吧,其实就是针对数组子项的索引,因为数组有多个元素,每个元素都可能的key,如果有一个索引A作用在这个key上,这就是所谓的Multikey index

  • Geospatial Index 针对地理位置信息的索引

  • Text Index 支持全文搜索的索引,2.4才支持

  • Hashed Index , To support hash based sharding, MongoDB provides a hashed index (page 22) type, which indexes the hash of the value of a field.

同时,mongodb提供了两个索引的属性:

  • Unique 唯一性,保证索引作用的field上的value是唯一的。

  • Sparse 稀疏性,如果一个Collection中的某个field A 只存在于某些Document上,而 A 上同时建立了索引,那么用Sparse则会使查询操作直接忽略这些记录。

好了,概念说了很多,来讲一下索引的具体操作吧。创建一个索引很简单,看看下面这些代码:


// 单键索引
db.Student.ensureIndex({code:1});

// 复合索引
db.Student.ensureIndex({name:1,time:-1})

// Multikey Index
db.Student.ensureIndex({faver.id:1});

//  唯一索引
db.Student.ensureIndex({code:1},{unique:1});

// 唯一索引同时删除重复值
db.Student.ensureIndex({code:1},{unique:1,dropDups:1});

// 唯一稀疏索引
db.Student.ensureIndex({code:1},{unique:1,sparse:1});


获取一个Collection上面的集合信息

// 单个Collection
db.Student.getIndexes();

// DB中所有的Index
db.system.indexes.find();

删除索引

// 删除在某个field上面的索引
db.Student.dropIndex({name:1});

// 根据索引名删除
db.system.indexes.remove({name:"code_-1"})

如何修改索引呢?没有特定修改命令,一般是先删除,然后创建新的索引。

系统运行一段时间以后,随着数据的累加,业务需求的变化,可能会需要对索引进行重建(rebuild),则可以做这个操作:

db.collection.reIndex()

rebuild会先删除集合上的所有索引,包括_id索引,然后重建。这种操作往往和耗时,最好在系统资源充足的时候做。

细节

1. 限制

mongodb对索引的使用和管理也有一些限制

  • 索引key的总容量不能大于1024byte,否则以后的索引将创建不了

  • 单个集合不能超过64个索引

  • 单个索引的名字长度(包括命名空间)不能超过125 个字符

  • 复合索引最多只能作用在31个field上

  • 一个查询不能同时使用text and Geospatial 索引

上面列的只是一些大的限制,在具体场景中还有很多索引相互冲突,或者使用不当造成索引无法命中的情况,所以还要看看更细节的一些东西。

2. 使用策略

2.1 _id 主键索引

这个是系统自动创建的,不能删除,除非你Drop掉整个Collection。这个效率是非常高的,对于一些数据量很大,但是没有排序需求的集合(如日志表),在分页策略上应该使用_id来进行分页。

2.2 single 单键索引

mongodb 不限制你在任何field上面创建单键索引,但是一个查询一次只能使用一个索引($or子句可以使用多个),所以看看下面的情况会是这样的:

//存在两个索引:
{code:1},
{name:1}

//这里mongodb只会命中一个索引,具体是哪个由查询分析器决定
db.Student.find({code:{$lt:10},name:{$regex:/^a/}}).explain();
{
    "cursor" : "BtreeCursor name_1",
    "isMultiKey" : false,
    "n" : 1,
    "nscannedObjects" : 1,
    "nscanned" : 1,
    "nscannedObjectsAllPlans" : 4,
    "nscannedAllPlans" : 4,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "millis" : 46,
    "indexBounds" : {
        "name" : [
            [
                "a",
                "b"
            ]
        ]
    },
    "server" : "pormatoMacBook-Pro.local:27017"
}

索引还存在排序问题,{a:1}升序 / {a:-1}降序,但是对于单键索引,排序的时候升序降序都会命中。如:

db.Student.find().sort({name:1});
db.Student.find().sort({name:-1});

2.3 复合索引

多数情况下,应该考虑复合索引而非单键索引,因为复合索引会包含部分单键索引。例如:
对于索引:
{a:1,b:1,c:1}
相当于该集合拥有了:
{a:1} , {a:1,b:1} , {a:1,b:1,c:1}
但是:
{b:1} ,{c:1} , {b:1,c:1} 是无法命中的。

如果排序也希望命中索引的话,这里分为两种情况:

  • 排序字段以索引开始键开头
// 因为查询条件中不存在索引开始键(a:1),要想命中索引,排序必须以索引开始键开头
db.mycoll.find({b:{$gt:1}}).sort({a:1,b:1,c:1});
  • 排序字段不以索引开始键开头
db.mycoll.find({a:{$gt:1}}).sort({b:1,c:1});

当然,排序里面还有更为细致的问题,就是查询条件如果有索引field的精准匹配(equal),则排序也能更简单:

db.mycoll.find({a:1}).sort({b:1});

同样,复合索引也存在索引反序问题,这里和单键索引一样,只有完全反序才能命中:
对于索引{a:1,b:-1}, {a:-1,b:1} 是可以命中的,反过来也成立。但是:{a:1,b:1}或者{a:-1,b:-1}是无法命中索引的。

3 MultiKey Index 多键索引

多键索引是作用在 array field上的element中的某个field上的索引。这个没有太多的特别之处,唯一要注意的是,如果一个索引是复合多键索引,那么这个索引的field中只能有一个array类型。例如:
{a:1,b:[{b1:1,b2:1}] 这个是Ok的, {a:[a1:1,a2:1],b:[{b1:1,b2:1}] 这种索引则是非法的。

其它

mongdb中还存在一种Cover Index的说法。它发生在如下的情况中:

  • all the fields in the query are part of an index, and

  • all the fields returned in the results are in the same index.

代码


db.mycoll.find({a:{$lt:100}},{a:1,_id:0}});

这个时候查询条件的field和 查询域field 完全一样,并且这个field刚好能命中索引的话,这个查询效率将非常的高,因为mongodb不会再去硬盘进行扫描,而是直接将Index信息返回。

这里需要知道的是如果在下面两种情况下,Cover Index将无法生效

  • any of the indexed fields in any of the documents in the collection includes an array. If an indexed field is an array, the index becomes a multi-key index , index and cannot support a covered query.
    数组field将直接会使索引变为多键索引

  • any of the indexed fields are fields in subdocuments. To index fields in subdocuments, use dot notation.
    查询域总是会返回整个子文档的root节点

基本的索引类型就是这么多了,接下来还有Text , Geo ,hash等较为复杂的索引类型,这个在以后的文章中再来分析。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容

  • 索引能够提高数据库的查询效率,没有索引的话,查询会进行全表扫描(scan every document in...
    zhglance阅读 2,017评论 0 6
  • 索引(index) 索引 index经常用于常用的查询,如果设计得好,在创建索引之后的查询会有提升效率的效果。但是...
    我看不见阅读 3,229评论 0 6
  • Spark SQL, DataFrames and Datasets Guide Overview SQL Dat...
    草里有只羊阅读 18,278评论 0 85
  • 早上六点,杜塞尔多夫天还没有亮,六点五十五分的火车去阿姆斯特丹。昨晚查了地铁这会还没开,想着大不了走去火车站,但是...
    吴俐温哪阅读 891评论 0 1
  • 第一次感觉到“我有几千万里的山光想与你说,这沿途的星辰也想粒粒分明摘取下来交由你,你可不可以等我。” ​我对你的喜...
    ryyx阅读 428评论 0 0