MongoDB索引

索引的作用是用来加速查询,数据库索引与书籍索引类似,创建数据库索引好像确定何如组织书的索引一样。

# 批量查询数据
for(var i=0; i<30000; i++){
    db.books.insert({name:'book'+i, sort:i});
}
db.books.count();

# 查看查询计划
db.books.find(query).explain();
"cursor":"BasicCursor",//说明没有索引发挥作用
"nscannedObjects":1000,//理论上要扫描的行数

# 计算查询效率
var begin = new Date();
db.books.find({sort:30000});
var end = new Date();
print(end-begin);

# 创建索引,1表示正序,-1表示倒序。
db.books.ensureIndex({sort:1});
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1.0
}

explain

只要对游标调用explain()会返回一个文档而非游标本身,explain()会返回查询使用的索引情况,耗时及扫描文档数的统计信息。

强制查询使用指定索引

# 指定索引必须是已经创建了的索引
db.books.find({name:'bookname1', sort:1}).hint({name:-1})

# 查看数据库已建立的索引
db.system.indexes.find();
db.system.namespaces.find();

1 创建索引

索引提高查询速度,但会降低写入速度,权衡常用查询字段,不必在太多字段上创建索引。在MongoDB中索引可按字段升序或降序来创建,便于排序。默认使用btree来组织索引文件,在2.4版本后允许建立hash索引。

  • 创建索引时索引的方向,1为正序索引,-1为倒序索引。
  • 索引的创建在提高查询性能的同时会影响插入的性能,对于经常查询少插入的文档可考虑使用索引。
  • 复合索引要注意索引的先后顺序
  • 索引不是万能的
  • 排序时大数据量可考虑添加索引

1.1 索引类型

索引的作用类型分为单列索引、多列索引、子文档索引。

# 查看查询计划
db.books.find(query).explain()
"cursor":"BasicCursor",//说明没有索引发挥作用
"nscannedObjects":1000,//理论上要扫描的行数

# 创建单列索引
db.books.sureIndex({field:1/-1})
# 创建多列索引(复合索引)
db.books.sureIndex({field:1/-1, field:1/-1...})
# 创建子文档索引
db.books.sureIndex({field.subfield:1/-1})

# 查看查询计划
db.books.find(query).explain()
"cursor":"BtreeCursor sn_1",//使用btree索引
"nscannedObjects":1000,//理论上要扫描的行数

创建索引的缺点是每次插入、更新、删除时会产生额外的开销。这是因为数据库不但需要执行这些操作,还需将这些操作在集合中的索引中标记。因此,要尽可能少创建索引。每个集合默认最大索引个数为64个。

# 查看当前索引状态
db.books.getIndexes()

一般来说或要是查询返回集合中一半以上的结果,用表扫描会比几乎每条文档都查询索引要高效。查询是否存在某个键或检查某个布尔值类型,使没必要建立索引的。

创建索引时需考虑什么呢?

  • 会做什么样的查询呢?其中哪些键需要索引呢?
  • 每个键的索引方向是怎样的呢?
  • 如何应对扩展?有没有不同的键的排列可使用常用数据更多地保留在内存中?

1.2 索引名称

集合中每个索引默认使用字符串命名并具有唯一性,其格式为 keyname1_dir1_keyname2_dir2_..._keynameN_dirN,keyname表示索引的键,dir表示索引的方向(1正序 -1逆序)。索引太多时可手工指定索引名称。

# 创建索引同时指定索引名称
db.books.ensureIndex({name:-1}, {name:'bookname'});
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 2,
    "numIndexesAfter" : 3,
    "ok" : 1.0
}
# 为内嵌文档的键建立索引
db.blogs.ensureIndex({'comments.date': 1});

1.3 排序索引

随着集合的增长,需针对查询中大量的排序做索引。若对无索引的键调动sort,MongoDB需将所有数据提取到内存来排序??勺鑫扌蚺判蚴庇猩舷薜?,是不可能在内存中做T级别的数据排序。一旦集合达到不能再内存中排序,MongoDB会报错。按照排序来索引以便让MongoDB按顺序提取数据,在排序大数据时不必担心耗光内存。

创建索引时,程序执行过程会暂时锁表,该如何解决呢?

# 为了不影响查询,创建索引可在后台执行。
db.books.ensureIndex({name:-1}, {background:true})

通常来说要尽量避免让服务器做表扫描,因为集合很大时会非常慢。实践证明,一定要创建查询中用到的所有健的索引。

2 删除索引

# 精确删除
db.books.dropIndex({field:1/-1});//删除某列字段的单个索引
db.runCommand({dropIndexes:'name', index:'name_1'});

# 批量删除
db.books.dropIndexes();//删除所有索引
db.runCommand({dropIndexes:'name', index:'*'})

3 索引性质

3.1 唯一索引

建立唯一索引可解决插入重复的数据,以确保集合文档指定键是唯一值。

db.books.ensureIndex({name:-1}, {unique:true});

在插入数据时并不检查文档是否已经插入过,为避免插入的文档包含于唯一键重复的值,可能要用安全插入才能满足要求。这样,在插入文档时会看到存在重复键错误的提示。

默认的_id与普通的唯一索引的区别是,_id的索引时无法删除的。

创建索引后若无对应的键,索引会将其作为null存储。若对键建立唯一索引,但插入了多个缺少该索引键的文档,则由于文档包含null值而导致插入失败。

消除重复

倘若建立唯一索引之前已存在重复数据,该怎么办呢?可将包含重复值的文档都删掉,dropDups选项可保留发现的第一个文档,而删除剩余具有重复值的文档。对于重要数据而言,应写脚本做预处理比较稳妥。

db.books.ensureIndex({name:-1}, {unique:true, dropDups:true})

复合唯一索引

创建复合唯一索引时,单个键值可相同,只要所有健的值组合起来不同即可。

GridFS是MongoDB中存储大文件的标准方式,用到了复合唯一索引。存储文件内存的集合有一个复合唯一索引{files_id:1, n:1}。

3.2 稀疏索引

若针对字段做索引时且不含字段的文档,将不建立索引。与之相对的是普通索引,它会把文档的字段值默认为NULL并建立索引。稀疏索引适用于小部分文档含有某字段时使用。

db.collection.ensureIndex({field:1/-1}, {sparse:true})

3.3 哈希索引

btree和二叉树,对于顺序读取具有优势。hash取决于hash算法,根据hash算法获得硬盘保存位置,对于散列的数据,仅通过hash计算即可获取数据,由于天生无顺序,因此适合于离散的数据。

哈希索引速度比普通索引快,但不能对范围查询进行优化,适用于随机性强的散列数据。

db.collection.ensureIndex({field:'hashed'})

4 重建索引

数据表经多次修改后导致文件产生空洞,索引文件也是如此。因此可通过重建索引来提高索引的查询效率,类似MySQL的optimize表。

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

推荐阅读更多精彩内容