- 浏览: 28675 次
- 性别:
- 来自: 郑州
最新评论
-
zcq100:
非常感谢楼主的分享
MongoDB学习笔记之四 Indexes -
kisa77:
shiwei8097 写道谢谢分享,size和max到底的区别 ...
MongoDB学习笔记之二 Collections -
shiwei8097:
谢谢分享,
size和max到底的区别好像说明的不够清楚。
MongoDB学习笔记之二 Collections
四、索引
基本
在shell中,你可以通过使用 ensuerIndex() 函数来创建索引,可对某个特定的1个或多个字段索引,根据mongo手册中提供的例子,要对键值"j"进行索引,可执行下列命令
db.things.ensureIndex({j:1}); //参数1代表升序,相反的-1代表降序
ensureIndex()函数只有在索引不存在的时候才会创建。跟mysql类似,访问一个有索引的字段要比访问一个未被索引的字段速度要快得多。可以执行 db.things.getIndexes();命令来查看things这个Collections下的所有索引。
默认索引
Mongo会为_id建立索引,_id比较特殊不能被删除,且值是唯一的。
Embedded Keys (子键?不确定的翻译)
使用mongo你甚至可以对一个子键进行索引,例如
db.things.ensureIndex({"address.city": 1})
Document as Keys(索引一个document)
索引字段可能是任意类型,包括documents:
db.factories.insert( { name: "xyz", metro: { city: "New York", state: "NY" } } ); db.factories.ensureIndex( { metro : 1 } ); // this query can use the above index: db.factories.find( { metro: { city: "New York", state: "NY" } } );
另外一种方法是创建混合索引:
db.factories.ensureIndex( { "metro.city" : 1, "metro.state" : 1 } ); // these queries can use the above index: db.factories.find( { "metro.city" : "New York", "metro.state" : "NY" } ); db.factories.find( { "metro.city" : "New York" } ); db.factories.find().sort( { "metro.city" : 1, "metro.state" : 1 } ); db.factories.find().sort( { "metro.city" : 1 } )
两种方法各有优缺点。第一种对整个document进行索引,排序是预定义的按插入BSON数据的先后升序排列。使用混合索引的话,可以混合正序和倒序。the query optimizer will then be able to use the index for queries on solely the first key(s) in the index too.(这句不知改如何理解)
数组
当一个被索引的值是数组时,MongoDB会索引这个数组中的每一个元素。更多信息在 multikey模块有详细说明
Compound Keys Indexes (混合键索引)
除了Single-key单键基本索引之外,Mongo也支持“多键”混合索引,跟单键索引不同的一点就是使用 ensureIndex()创建的时候填写多个键值
db.things.ensureIndex({j:1, name:-1});
数字参数指定索引的方向,1为正序,-1为倒序。方向对单键索引和随机存不要紧,但如果你要执行分组和排序操作的时候,它就非常重要了。
Unique Indexes (唯一索引)
作用跟关系型数据库中的唯一索引一样,创建方法为
db.things.ensureIndex({firstname: 1}, {unique: true});
Missing Keys
用唯一索引保存文件到集合里时,会将所有缺失的索引键作为空值插入,因此缺失相同的索引键插入不同的文件是不可能的。
db.things.ensureIndex({firstname: 1}, {unique: true}); db.things.save({lastname: "Smith"}); // Next operation will fail because of the unique index on firstname. db.things.save({lastname: "Jones"});
Duplicate Values
在一个存在重复值的键上是无法创建唯一索引的,如果仍要创立必须设置dropDups参数,这样做会留下第一个重复值,以后遇到的含有重复值的记录都会被删除。
db.things.ensureIndex({firstname : 1}, {unique : true, dropDups : true})
在1.3.2之前的版本,数据库在创建索引的时候会处于锁定状态,其他操作暂时无法执行。
Dropping Indexes
删除某个Collection下的所有索引:
db.collection.dropIndexes();
Geospatial Indexing
MongoDB支持二维空间索引,这是设计时考虑到基于位置的查询。例如“找到离目标位置最近的N条记录”。可以有效地作为附加条件过滤。
如果需要使用这种索引,应确定对象中存储的字段是子对象或数组,前两个元素为X,Y坐标(或者Y,X坐标,保持一致即可。it might be advisible to use order-preserving dictionaries/hashes in your client code, to ensure consistency),一些例子:
{ loc : [ 50 , 30 ] } { loc : { x : 50 , y : 30 } } { loc : { foo : 50 , y : 30 } } { loc : { lat : 40.739037, long: 73.992964 } }
Creating the Index
db.places.ensureIndex( { loc : "2d" } ) //应该是固定格式
默认的,Mongo假设你索引的是经度/维度,因此配置了一个从-180到180的取值范围,如果你想索引更多,可以指定该参数:
db.places.ensureIndex( { loc : "2d" } , { min : -500 , max : 500 } )
上面的代码将衡量索引保证存入的值在-500到500的范围之内。一般来说geo索引仅限于正方形以内且不包括边界以以外的范围,不能再边界上插入值,比如使用上面的代码,点(-500,-500)是不能被插入的。
目前为止,每个Collection只能建立一个geo索引
Querying
该索引可以被用来精确匹配:
db.places.find( { loc : [50,50] } )
对于geo索引来说,更重要的是一个查询可以找到目标点附近的点,不必要精确匹配。
db.places.find( { loc : { $near : [50,50] } } )
上面的一句将按离目标点(50,50)距离最近的100个点(距离倒序排列),如果想指定返回的结果个数,可以使用limit()函数,若不指定,默认是返回100个。
db.places.find( { loc : { $near : [50,50] } } ).limit(20)
Compound Indexes
Mongo空间索引可选的支持第二字段索引.如果想用坐标和其他属性同事作为条件查询,把这个属性也一同索引,其他属性带注释性的加入索引中可使过滤更快。
db.places.ensureIndex( { location : "2d" , category : 1 } ); db.places.find( { location : { $near : [50,50] }, category : 'coffee' } );
geoNear Command
虽然find()语法为查询的首选,Mongo也提供来了 geoNear 命令来执行相似的函数。geoNear命令有一个额外的好处是结果中返回距离目标点的距离,以及一些利于排除故障的信息。
> db.runCommand( { geoNear : "places" , near : [50,50], num : 10 } ); > db.runCommand({geoNear:"asdf", near:[50,50]}) { "ns" : "test.places", "near" : "1100110000001111110000001111110000001111110000001111", "results" : [ { "dis" : 69.29646421910687, "obj" : { "_id" : ObjectId("4b8bd6b93b83c574d8760280"), "y" : [ 1, 1 ], "category" : "Coffee" } }, { "dis" : 69.29646421910687, "obj" : { "_id" : ObjectId("4b8bd6b03b83c574d876027f"), "y" : [ 1, 1 ] } } ], "stats" : { "time" : 0, "btreelocs" : 1, "btreelocs" : 1, "nscanned" : 2, "nscanned" : 2, "objectsLoaded" : 2, "objectsLoaded" : 2, "avgDistance" : 69.29646421910687 }, "ok" : 1 }
上面的命令将返回10条距离点(50,50)最近的记录,loc字段由该collection的空间索引自动检测后决定。
如果你想添加一条过滤条件,可以这样:
> db.runCommand( { geoNear : "places" , near : [ 50 , 50 ], num : 10, ... query : { type : "museum" } } );
Bounds Queries
v1.3.4版本以上
$within 参数可以代替$near来查找一个形状之内结果。同时,也支持$box(矩形)和$center(圆环)
想要查找一个一个矩形之内所有的点,必须制定该矩形的左下角和右上角坐标:
> box = [[40, 40], [60, 60]] > db.places.find({"loc" : {"$within" : {"$box" : box}}})
Multikeys
Mongo提供了一个有趣的特性可以自动索引数组对象的值,一个好的例子就是文章标签,试想你要存储含有多个分类名称的文章标签
$ dbshell > db.articles.save( { name: "Warm Weather", author: "Steve", tags: ['weather', 'hot', 'record', 'april'] } ) > db.articles.find() {"name" : "Warm Weather" , "author" : "Steve" , "tags" : ["weather","hot","record","april"] , "_id" : "497ce4051ca9ca6d3efca323"}
可以很轻易的用一个查询得到这个数组中特定的值
> db.articles.find( { tags: 'april' } ) {"name" : "Warm Weather" , "author" : "Steve" , "tags" : ["weather","hot","record","april"] , "_id" : "497ce4051ca9ca6d3efca323"}
我们也可以对tag数组进行索引,对数组元素创建索引,数组中的每个元素就都会被索引。
> db.articles.ensureIndex( { tags : 1 } ) true > db.articles.find( { tags: 'april' } ) {"name" : "Warm Weather" , "author" : "Steve" , "tags" : ["weather","hot","record","april"] , "_id" : "497ce4051ca9ca6d3efca323"} > db.articles.find( { tags: 'april' } ).explain() {"cursor" : "BtreeCursor tags_1" , "startKey" : {"tags" : "april"} , "endKey" : {"tags" : "april"} , "nscanned" : 1 , "n" : 1 , "millis" : 0 }
Embedded object fields in an array
此外同样的方法也可以用于字段内容是对象的情况
> db.posts.find( { "comments.author" : "julie" } ) {"title" : "How the west was won" , "comments" : [{"text" : "great!" , "author" : "sam"}, {"text" : "ok" , "author" : "julie"}], "_id" : "497ce79f1ca9ca6d3efca325"}
Querying on all values in a given set
通过使用$all查询选项, a set of values may be supplied each of which must be present in a matching object field.
> db.articles.find( { tags: { $all: [ 'april', 'record' ] } } ) {"name" : "Warm Weather" , "author" : "Steve" , "tags" : ["weather","hot","record","april"] , "_id" : "497ce4051ca9ca6d3efca323"} > db.articles.find( { tags: { $all: [ 'april', 'june' ] } } ) > // no matches
Indexing Advice and FAQ
Indexing Strategies
下面使一些常见创建高效索引的策略
如果经常查询单个字段,建立一个单键索引即可。
还有常见的唯一索引
然而一般都需要查询多个字段还有排序,这时组合索引是最合适的
db.comments.find({ tags : 'mongodb'}).sort({ created_at : -1 });
建立合适的索引:
db.comments.ensureIndex({tags : 1, created_at : -1});
注意:上面的代码,如果我们想按created_at正排序的话,会很低效。
One index per query
查询多个字段时有时被认为使用多个索引好一些,但是对于Mongo这并不合适。如果你有一个查询想得到多个字段而且还希望此查询使用一个高效的索引,使用组合键索引
Make sure your indexes can fit in RAM.
命令行下提供了一个命令来返回指定Collection的索引大小:
db.comments.totalIndexSize(); 65443
如果你的查询看起来很缓慢,就应该检测一下索引足够小以适合内存。举个例子,如果你运行一个4G内存的机器而你的索引有3G大小,这时候你的索引大小跟内存也许就不是很匹配,你需要添加内存或检测所有索引确定是不是所有都是游泳的。
Be careful about single-key indexes with low selectivity.
假设有一个字段名为'status',含有值'processeed'和'new',在status上建立一个索引的话,这个索引就是 低选择性的(low-selectivity),意味着改索引除了占用空间以外对于定位记录没有太大帮助。
更好的方案,根据查询,创建一个包含有低选择性字段的混合索引,例如,你可以在'status'和'created_at'上创建混合索引。
Another option, again depending on your use case, might be to use separate collections, one for each status. As with all the advice here, experimentation and benchmarks will help you choose the best approach.
Use explain
MongoDB包含一个解释语法explain(),可以显示查询语句是怎样被执行的。需要特别说明的,无论是否使用索引,explain()语法可用于shell和各种语言的驱动中。
db.comments.find({ tags : 'mongodb'}).sort({ created_at : -1 }).explain();
该语句返回很多有用的信息,包括被扫描过的记录数目、以毫秒为单位的任务查询时间、查询优化器尝试的哪些索引以及最终采用的索引。
Exp:
> db.nemok.find().explain() { "cursor" : "BasicCursor", "startKey" : { }, "endKey" : { }, "nscanned" : 1017, "n" : 1017, "millis" : 0, "oldPlan" : { "cursor" : "BasicCursor", "startKey" : { }, "endKey" : { } }, "allPlans" : [ { "cursor" : "BasicCursor", "startKey" : { }, "endKey" : { } } ] }
cursor:该值为BasicCursor 和 BtreeCursor其中的一个。第二个值代表此次查询使用了索引。
nscanned:扫描的文档数目。
n:查询返回的结果条数,n的值越接近nscanned的值越好,尽量避免一次查询扫描整个Collection。
millis:返回此次查询消耗的毫秒数
Pay attention to the read/write ratio of your application.
这一点很重要,索引的优缺点,不再赘述。
Indexing Properties
下面是一些组合索引的性能问题,需要注意
假设创建一个三个字段的组合索引:
db.foo.ensureIndex({a: 1, b: 1, c: 1})
This information is no longer strictly correct in 1.6.0+; compound indexes can now be used to service queries where range or filter fields are used within the compound index, not just fields used from left to right. Please run explain to see how the compound index is used.
1. The sort column must be the last column used in the index.
Good:
- find(a=1).sort(a)
- find(a=1).sort(b)
- find(a=1, b=2).sort(c)
Bad:
- find(a=1).sort(c)
- even though c is the last column used in the index, a is that last column used, so you can only sort on a or b.
2. The range query must also be the last column in an index. This is an axiom of 1 above.
Good:
- find(a=1,b>2)
- find(a>1 and a<10)
- find(a>1 and a<10).sort(a)
Bad:
- find(a>1, b=2)
3. Only use a range query or sort on one column.
Good:
- find(a=1,b=2).sort(c)
- find(a=1,b>2)
- find(a=1,b>2 and b<4)
- find(a=1,b>2).sort(b)
Bad:
- find(a>1,b>2)
- find(a=1,b>2).sort(c)
4. Conserve indexes by re-ordering columns used on equality (non-range) queries.
Imagine you have the following two queries:
- find(a=1,b=1,d=1)
- find(a=1,b=1,c=1,d=1)
A single index defined on a, b, c, and d can be used for both queries.
If, however, you need to sort on the final value, you might need two indexes
5. MongoDB's $ne or $nin operator's aren't efficient with indexes.
- When excluding just a few documents, it's better to retrieve extra rows from MongoDB and do the exclusion on the client side.
FAQ
I've started building an index, and the database has stopped responding. What's going on? What do I do?
Building an index can be an IO-intensive operation, especially you have a large collection. This is true on any database system that supports secondary indexes, including MySQL. If you'll need to build an index on a large collection in the future, you'll probably want to consider building the index in the background, a feature available beginning with 1.3.2. See the docs on background indexing for more info.
As for the long-building index, you only have a few options. You can either wait for the index to finish building or kill the current operation (see killOp() ). If you choose the latter, the partial index will be deleted.
I'm using $ne or $nin in a query, and while it uses the index, it's still slow. What's happening?
The problem with $ne and $nin is that much of an index will match queries like these. If you need to use $nin, it's often best to make sure that an additional, more selective criterion is part of the query.
相关推荐
mongodb学习笔记资料,从安装到操作库collection 对document的crud 索引 replicaSet sharding 备份与恢复
自己在学习MongoDB的一些笔记,里面有各个查询选择器的使用截图,还有一些索引的介绍。
MongoDB 学习笔记 本文档是 MongoDB 学习笔记,涵盖了 NoSQL、Cache、运行平台等多个方面的知识点。 一、NoSQL 数据库 MongoDB MongoDB 是一个强大、灵活、可扩展性好的文档数据存储器,可以完成大部分关系数据库...
本篇学习笔记将从基础操作到高级功能,详细阐述MongoDB的关键知识点。 首先,MongoDB的基本单元是集合(collection),类似于关系型数据库中的表,而集合中的元素称为文档(document),文档是键值对的集合,类似于...
首先,`mongodb_and_python`学习笔记可能涵盖了如何使用Python编程语言与MongoDB进行交互。Python是常见的MongoDB驱动程序之一,通过PyMongo库,开发者可以方便地执行CRUD(创建、读取、更新、删除)操作,构建复杂...
mongodb学习笔记 MongoDB 是一个基于分布式文件存储的开源数据库系统,主要用于处理大量数据的存储和查询。以下是 MongoDB 的一些基本操作和技巧: 插入文档 MongoDB 中可以使用 `insert` 方法来插入文档,例如 ...
总结的MongoDB的学习笔记,基本上包括了MongoDB的方方面面,每个知识点,都有示例代码,有需要的朋友,可以下载下来进一步补充完善。
MongoDB 是一种流行的开源、非关系型数据库系统,以其灵活性、高性能和易用性而备受开发者青睐。在本文中,我们将深入探讨 ...在实际项目中,学习和掌握 MongoDB 及其驱动程序能够帮助你更好地应对现代数据存储需求。
本压缩包“mongoDB学习笔记及工具.zip”包含了一些资源,帮助你深入理解和掌握MongoDB的相关知识。 1. **笔记(note.txt)**: 这个文件可能是对MongoDB的基础概念、安装过程、基本操作和进阶特性的详细记录。笔记...
MongoDB是一种流行的NoSQL数据库,它的索引机制与传统的关系型数据库类似,旨在提升查询和排序的速度。在MongoDB中,索引对于优化查询性能至关重要,尤其在处理大量数据时。下面将详细介绍MongoDB中不同类型的索引...
### MongoDB 学习笔记知识点详解 #### 一、MongoDB 命令行基础操作 **1.1 帮助命令** - **help**:显示 MongoDB shell 的基本帮助信息。 - **db.help()**:提供当前数据库的帮助信息。 - **db.mycoll.help()**:...
MongoDB 入门教程笔记
MongoDB的集合(collection)可以看做关系型数据库的表,文档对象(document)可以看做关系型数据库的一条记录。但两者并不完全对等。表的结构是固定的,MongoDB集合并没有这个约束;另外,存入集合的文档对象甚至...
以下是对MongoDB学习的一些关键知识点的详细解释: 1. **MongoDB的基本概念**:MongoDB以集合(Collections)的形式存储数据,集合相当于关系型数据库中的表。集合内包含文档(Documents),文档是JSON格式的数据...