赞
踩
不使用索引的查询是全表查询,有索引的话则直接在索引中查找,然后跳转到目标文档的位置
使用 explain( "executionStats" )
查看MongoDB 在执行查询过程的细节,包括使用了哪个索引以及如何使用
for (i=0; i<100000;i++) { db.test.insert({ "i": i, "username": "user" + i, "age": Math.floor(Math.random()*120), "created": new Date() }); } db.test.find({"username": "user101"}).explain("executionStats") /* ... "executionStats" : { "executionSuccess" : true, // 执行是否成功 "nReturned" : 1, // 返回的文档数 "executionTimeMillis" : 81, // 执行的时间 "totalKeysExamined" : 0, "totalDocsExamined" : 100000, // 总共检查了多少个文档 "executionStages" : { "stage" : "COLLSCAN", "filter" : { "username" : { "$eq" : "user101" } }, "nReturned" : 1, "executionTimeMillisEstimate" : 0, "works" : 100002, "advanced" : 1, "needTime" : 100000, "needYield" : 0, "saveState" : 781, "restoreState" : 781, "isEOF" : 1, "direction" : "forward", "docsExamined" : 100000 } }, ... */
创建索引可以减少每次查询扫描文档的数量,大大地提升查询速度,代价是每次写操作都将更加耗时,因为不仅要更新文档还要更新集合上的所有索引
db.collection.createIndex(keys, options)
复合索引
- 复合索引就是建立在多个字段上的索引,
db.test.createIndex( { "age": 1, "username": 1 })
- 每个索引条目包含
age
和username
字段,并指向文档在磁盘上的存储位置- 选择索引键的方向:1 - 升序,2 - 降序
- 使用覆盖索引:即索引中包含用户请求的所有字段
- 隐式索引:拥有 N 个键的复合索引相当于可以使用前 M(M < N) 个键组成的索引
索引对象(即嵌套文档)和数组
索引嵌套文档
- 可以对单个子字段索引,使用
childDoc.field
形式- 也可以对嵌套文档本身索引,只会提高整个子文档的查询速度
索引数组
- 实际是对每一个元素建立一个索引条目(会导致更新操作代价高昂)
- 数组索引不包含位置信息,无法通过数组的index查找元素
- 一个数组索引中的数组字段最多只能有一个
多键索引
- 某个索引键的值在文档中是数组,则该索引被标记为多键索引(
isMultikey: true
)- 多键索引状态不会改变
- 速度相对慢一些
索引基数
cardinality
:集合中某个字段拥有不同值的数量explain( ):提供大量与查询相关的信息,对于任意查询都可在最后添加一个explain( )
hint( ): 强制MongoDB使用某个索引
查询优化器
- 如一个索引可以精确匹配一个查询,查询优化器直接使用该索引
- 否则,可能多个索引适合,则从可能的索引子集中为每次查询计划选择一个,每个查询计划并行执行,先返回100个结果的优胜,其它查询计划中止并被缓存,直到集合数据发生大变动
唯一索引
db.test.ensureIndex( { "username": 1 }, { "unique": true } )
:确保集合的每个文档的指定键有唯一值- 插入含有重复键时会报错
E11000 duplicate key error index: ...
_id
就是唯一索引- 可以创建复合唯一索引,单个键的值可以相同,但所有键的组合值必须唯一
- 如果集合中已经存在重复值时,创建唯一索引会失败,可以使用
db.test.ensureIndex( { "username": 1 }, { "unique": true , "dropDups": true } )
去重dropDups
会强制建立唯一索引,太粗暴,不可控,重要数据尽量避免使用
稀疏索引
- 唯一索引会把
null
看作值,因此无法插入多个缺少唯一索引中的键的文档- 可以使用
db.test.ensureIndex( { "username": 1 }, { "unique": true , "sprase": true } )
创建稀疏索引,则该字段可选,但是存在该字段则必须唯一
创建的索引可以在 system.indexes
看到其元信息
可执行 db.collection.getIndexes( )
查看指定集合上的所有索引信息
db.test.getIndexes() /* [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.test" }, { "v" : 2, "key" : { "username" : 1 }, "name" : "username_1", "ns" : "test.test" }, { "v" : 2, "key" : { "age" : 1, "username" : 1 }, "name" : "age_1_username_1", "ns" : "test.test" } ] */
标识索引:使用 db.test.ensureIndex({" age": 1, "username": 1}, {"name": "newIndexName"})
自定义索引名称
修改索引:使用 db.test.dropIndex("name")
删除不需要的索引
基本概念
- “普通”集合是动态创建的,会自动增长以容纳更多的数据
- 固定集合的大小固定,集合空间满后插入文档则会自动删除最老的文档
- 固定集合不可分片
- 固定集合可用于记录日志
创建固定集合
db.createCollection("my_collection", {"capped": true, "size": 1000, "max": 100})
:创建大小为 1000 字节的固定集合,max
指定文档的最大数量db.runCommand({"convertToCapped": "test2", "size": 1000})
:将常规集合转为固定集合- 固定集合创建之后不可变,只能进行删除操作
自然排序
db.my_collection.find().sort({ "$natural": 1 })
:自然排序即文档的插入顺序
循环游标:只能用于固定集合
没有 _id
索引的集合
- 默认每个集合都有
_id
索引- 创建集合时设置
autoIndexId: false
会创建没有_id
索引的集合,不建议如此操作
具有声明周期的索引(time-to-live index)
TTL 索引为每个文档设置一个超时时间
创建超时时间为24小时的TTL 索引
db.test.ensureIndex({" age": 1,}, {"expireAfterSecs": 60*60*24})
TTL 索引不能是复合索引
db.test.ensureIndex({" comments": "text"})
db.test.find({$text: {$search: "abc"}})
GridFS 是 MongoDB 的一种存储机制,用来存储大型二进制文件
优点:
- 可代替独立的文件存储工具
- 同一目录下存储大量文件
- 文件存储的集中度较高,MongoDB 以 2GB 为单位来分配数据文件
缺陷:
- 性能较低
- 无法直接修改文档,需要先删除已有文档,在保存整个新的文档
- 将文件作为多个文档存储,无法在同一时间问文件的所有块加锁
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。