文章19 | 阅读 11311 | 点赞0
索引本质上是树,最小的值在最左边的叶子上,最大的值在最右边的叶子上,使用索引可以提高查询速度(而不用全表扫描),也可以预防脏数据的插入(如唯一索引)。索引即支持普通字段也支持内嵌文档中某个键和数组元素进行索引
对某个键按照升续或降续创建索引,查询时首先根据查询条件查找到对应 的索引条目找到,然后找对索引条目对应的文档指针(文档在磁盘上的存储位置),根据文档指针再去磁盘中找到相应的文档,整个过程不需要扫描全表,速度比较快。
[“along”] ----> 0x0c965148(文档指针)
…
[“zhangsan”] ----> 0x0c965148(文档指针)
// 创建索引
db.collection.createIndex(keys, options);
// 查询索引
db.collection.getIndexes(filter);
// 删除索引
db.collection.dropIndex("IndexName");
// 删除所有索引
db.collection.dropIndexes()
// explain 查看查询是否走索引
// "stage" : "COLLSCAN", 表示全集合扫描
// "stage" : "IXSCAN" ,基于索引的扫描
db.collection.find(query,options).explain(options)
> db.foo.createIndex({"username": 1}, {"unique": true})
> db.foo.insert({"username": "mengday", "email": "mengday@163.com", "age": 26})
WriteResult({ "nInserted" : 1 })
// username 重复会报错
> db.foo.insert({"username": "mengday", "email": "mengday2@163.com"})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.foo index: username_1 dup key: { : \"mengday\" }"
}
})
// 第一次 插入不包含索引键的文档,插入成功,不包含索引键系统会默认为索引键的值为null
> db.foo.insert({"email": "mengday3@163.com"})
WriteResult({ "nInserted" : 1 })
// 第二次插入不包含唯一索引的键,插入失败,因为不包含键,键的值就null,第一次已经有一个值为null, 再插入null,就是重复
> db.foo.insert({"email": "mengday4@163.com"})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.foo index: username_1 dup key: { : null }"
}
})
// 对多个字段创建唯一索引(关系数据库中的联合主键)
db.foo.createIndex({"username": 1, "nickname": 1}, {"unique": true})
>
MongoDB是无结构型的NoSQL,同一个集合中的每条文档可以包含某个键,也可以不包含,为了达到如果文档中包含索引键,索引键的值必须唯一,如果不包含索引键那么不用校验唯一的效果,可以在创建索引时使用sparse: true, 也就是稀疏索引。
> db.foo.drop()
> db.foo.createIndex({"username": 1}, {"unique": true, "sparse": true})
// 对于不包含的索引字段在插入时不校验索引
> db.foo.insert({"email": "mengday1@163.com"})
WriteResult({ "nInserted" : 1 })
> db.foo.insert({"email": "mengday2@163.com"})
WriteResult({ "nInserted" : 1 })
> db.foo.insert({"username": "mengday3", "email": "mengday3@163.com"})
WriteResult({ "nInserted" : 1 })
> db.foo.insert({"username": "mengday3", "email": "mengday3@163.com"})
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.foo index: username_1 dup key: { : \"mengday3\" }"
}
})
稀疏索引:对不存在的键就不进行索引,也就是该文档上没有建立索引,索引条目中也不包含 索引键为null的索引条目,所以再次插入不包含索引键的文档不会报错,直接插入。注意:稀疏索引不光和唯一索引配合使用,也可以单独使用。
唯一索引的目的是为了让数据库的某个字段的值唯一,为了确保数据的都是合法的,但是唯一索引在插入数据时会对数据进行检查,一旦重复会抛出异常,效率会比较低,唯一索引只是保证数据库数据唯一的最后一种手段,而不是最佳方式,更不是唯一方式,为了保证效率最好采用别的解决方案来保证数据的唯一合法性,尽量减少数据库的压力。
创建索引时可以对一个字段创建索引,也可以对多个字段创建索引,对多个字段创建索引被称为 复合索引或者组合索引。
对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。
复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由 { userid: 1, score: -1 } 组成,则索引首先按userid正序排序,然后在每个userid的值内,再在按score倒序排序。
> db.user.find()
{ "_id" : 1, "username" : "zhangsan", "age" : 25 }
{ "_id" : 2, "username" : "lisi", "age" : 18 }
{ "_id" : 3, "username" : "wangwu", "age" : 28 }
{ "_id" : 4, "username" : "fengwu", "age" : 27 }
>
// 1:为索引值以升续的方式创建索引条目,-1:代表降续
> db.user.createIndex({"username": 1})
// explain()函数用于查看当前查询的一些信息,比如使用使用了索引等
> db.user.find({"username": "wangwu"}).explain()
// 创建组合索引(以后台模式创建)
> db.user.createIndex({"username": 1, "age": 1}, {"background": true})
> db.user.find({"username": "wangwu", "age": 28})
// 如果查询时发现没有使用到索引,可以使用hint函数强制使用索引查询
> db.user.find().hint({"username": 1, "age": 1})
> db.user.update({"username": "zhangsan"}, {"$set": {"address": {"road": "yijiang", "code": 666}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 对内嵌文档中字段创建索引
> db.user.ensureIndex({"address.road": 1}, {"background": true})
> db.user.find({"address.road": "yijiang"}).explain()
// 对数组创建索引,就是对数组中的每个元素分别创建索引,而不是对整个数组建立索引,对数组的每一个元素都创建索引,那么维护索引的代价就比普通的值大
> db.user.update({"username": "zhangsan"}, {"$set": {"hobby": ["eat", "drink", "mm", "money"] }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.ensureIndex({"hobby": 1}, {"background": true})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 4,
"numIndexesAfter" : 5,
"ok" : 1
}
> db.user.find({"hobby": "mm"}).explain()
TTL索引是让文档的某个日期时间满足条件的时候自动删除文档
,这是一种特殊的索引,这种索引不是为了提高查询速度的,TTL索引类似于缓存,缓存时间到了就过期了,就要被删除了。
// expireAfterSeconds: 文档生存的时间,单位是秒,索引键是日期类型的
// 如果当期时间大于索引键的时间加上缓存时间就会删除该文档
> db.foo.createIndex({"create_at": 1}, {"expireAfterSeconds": 60})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}
全文索引是用于对长文本检索来使用的,是用正则表达式只能对字符串类型的值进行检索。注意:创建索引是一件比较耗时耗费资源的事情,而全文索引更是耗时更厉害,如果对索引键的内容比较长,需要对内容进行分词,会出现更严重的性能问题。
// 创建全文索引:字段:content, 键的类型:text(全文索引类型)
> db.blog.createIndex({"content": "text"})
> db.blog.insert({
"title": "MongoDB: The Definitive Guide",
"summary": "MongoDB Atlas Database as a Service",
"content": "The best way to deploy, operate, and scale MongoDB in the cloud. Available on AWS, Azure, and GoogleCloud Platform. Easily migrate your data to MongoDB Atlas with zero downtime."
})
// 使用全文索引进行查询
> db.blog.find({"$text":{"$search": "best"}})
{ "_id" : ObjectId("5986c5c94fbaf781302810e2"), "title" : "MongoDB: The Definitive Guide", "summary" : "MongoDB Atlas Database as a Service", "content
" : "The best way to deploy, operate, and scale MongoDB in the cloud. Available on AWS, Azure, and GoogleCloud Platform. Easily migrate your data to M
ongoDB Atlas with zero downtime." }
>
创建全文索引,建议在mongodb不忙的时候创建,mongodb的分词现在好像不支持中文,如果是对内容比较小的比如小于100个汉字的可以试用一下mongodb的全文索引,如果是对一篇很长的文章使用全文索引这是非常不合适的,这会把mongodb累死的,对于内容比较多可以采取其他技术如ElasticSearch、Solr等技术。
$where、$exists
。$not、$nin、$ne
。$in
操作符尽量不要使用$or
操作符,因为or: 是执行两次查询操作,然后将结果合并起来,类似于union all,能使用in(单次查询)就不要使用or操作符。什么时候创建索引?当需要对查询优化,或者经常使用某种查询的时候可以创建索引来提高查询效率。
应该选哪些字段创建索引?一般应该在基数比较高的键上建立索引,或者至少把基数较高的键放在复合索引的前面位置。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://monday.blog.csdn.net/article/details/76761339
内容来源于网络,如有侵权,请联系作者删除!