欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MongoDB 索引(Index)

程序员文章站 2022-05-13 16:26:26
...

一、索引的CRUD

创建索引:ensureIndex()

    db.collection.ensureIndex({"name":1})    为collection的name属性创建正序索引

    db.collection.ensureIndex({"name":1},{unique:true})    为collection的name属性创建正序唯一索引。

     db.collection.ensureIndex({"name":1},{unique:true,dropDups:true})   为collection的name属性创建正序唯一索引。剔除为唯一重复值(在建唯一索引前已经存在重复值)。

 

查看索引:getIndexes()

   db.system.indexes.find()  查看当前数据库的所有索引。 所有数据库都存在索引文档system.indexes

   db.system.namespaces.find() 查看当前数据库的所有索引。

   db.collection.getIndexes()  查询当前数据库中指定collection的索引。

删除索引:dropIndex()

   db.collection.dropIndex({"name":1})    删除collection中的name属性的索引。

   db.collection.dropIndex("name_1")      删除collection中索引名称为name_1的索引

   db.runCommand({dropIndexes:"collection",index:"indexName"})   删除当前数据库中collection文档的索引名称为indexName的索引。注意indexName是索引名称,不是文档的属性名称。

    db.runCommand({dropIndexes:"collection",index:"*"}) 删除当前数据库中collection文档的所有索引。

查询时指定索引:

  Hint 

     eg:db.user.find({name:'张三',sex:'男'}).hint({name:1});   #指定索引key

             db.user.find({name:'张三',sex:'男'}).hint("name_1");     #指定索引名称

     注意:查询时指定索引时指定索引必须存在。

     db.collection.getIndexes();  查询指定集合的索引列表

 

重建索引 reindex()

语法:db.collection.reIndex()

适用场景:一个表经过大量的修改后会导致表的文件上产生空洞,索引文件也是一样,

可以通过重建索引来提高索引的效率。

不好的地方:对于数据量大或者索引多的表来说,重建索引代价重大。

 

一般不需要重建索引,只有集合大小发生显巨变化或磁盘空间占用不成比例时才需要

 

二、索引的分类

   1、默认索引

 

    2、单列索引

 

    3、组合索引

 db.collection.ensureIndex({"provinceId":1,"isDied":1});

 

  注意:组合索引支持的索引查询只是索引的任意前缀索引字段。 

eg:

建表:

db.products.insert({

"_id": ObjectId("56c448bb4b3a77a13d33d5d6"),

"item": "Banana",

"category": ["food", "produce", "grocery"],

"location": "4th Street Store",

"stock": 4,

"type": "cases"

});

 新建索引:db.products.ensureIndex({"item":1,"location": 1,"stock": 1})

 

以下三个查询都不能使用索引:

db.products.find({"location":"4th Street Store"}).explain();

db.products.find({"stock":4}).explain();

db.products.find({"location":"4th Street Store","stock":4}).explain();

下面查询文档上说不能使用索引,但是实际可以使用,不知道为什么 20170220。

db.products.find({"item": "Banana","stock": 4}).explain();

MongoDB 支持索引的前缀查询。

 

    4、内嵌索引

     a,内嵌字段索引(Index on an Embedded Field)

#创建数据
db.records.insert({
  "_id": ObjectId("570c04a4ad233577f97dc459"),
  "score": 1034,
  "location": { state: "NY", city: "New York" }
})

 

#创建索引
db.records.createIndex( { "location.state": 1 } )

 

   

#使用索引查询
    #使用了索引    查询到了数据
    db.records.find( { "location.state": "NY" } ).explain();  
    #使用了索引   查询到了数据
    db.records.find( {"location.city": "New York","location.state": "NY" } ).explain();  
    #使用了索引   查询不到数据
    db.records.find( { location: { city: "New York", state: "NY" } } );

 

   b,内嵌文档索引(Index on an Embedded Documents)

   

#创建数据
db.user.insert(
    {
      name: {
              first: "Yukihiro",
              last: "Matsumoto"
            }
    }
);

db.user.insert(  
    {  
      name: {  
              first: "Yukihiro",  
              last: "Matsumoto",
              center:"center"
            }  
    }  
)

 

#创建索引
db.user.createIndex( { "name": 1 } );

 

#使用索引查询
#使用了索引    查询到了数据(第一条数据)
db.user.find( { name: { first: "Yukihiro", last: "Matsumoto" } } ).explain(); 
# 内嵌文档索引必须内嵌文档里面的内容完全匹配才能查出,所以这就是上面的查询为什么只返回了一条数据的理由  

#没有使用索引    查询到了数据(两条数据都查到了)
db.user.find(
   {
     "name.first": "Yukihiro",
     "name.last": "Matsumoto"
   }
).explain();

 

     内嵌文档索引

#建立索引前查询
db.collection.find({"contents.content":"传统美术"}).explain()
#建立索引
db.collection.ensureIndex({ "contents.content": 1} )
#建立索引后查询
db.collection.find({"contents.content":"传统美术"}).explain()

#建立索引前查询
db.collection.find({"contents":{$elemMatch:{"fieldId":"project_type","content":"传统美术"}}}).explain()
#建立索引
db.collection.ensureIndex({ "contents.fieldId": 1,"contents.content": 1} )
#建立索引后查询
db.collection.find({"contents":{$elemMatch:{"fieldId":"project_type","content":"传统美术"}}}).explain()
#建立索引后性能有了明显的提升。

 

 

    5、唯一索引  {unique:true}

        db.collection.ensureIndex({"name":1},{unique:true})    为collection的name属性创建正序唯一索引

    6、全文索引

        当前数据库开启全文索引:db.adminCommand({setParameter:true,textSearchEnabled:true})

        新建全文索引:db.collection.ensureIndex({"contents.content":"text"});

        使用全文索引进行查询:db.collection.find({$text:{$search:"景区"}})

        参考文章:http://www.ziqiangxuetang.com/mongodb/mongodb-text-search.html

        注意:一张表只能新建一个全文索引。

   7、哈希索引 {'field':'hashed'}

        哈希索引特点:速度比普通索引块,但是无法对范围查询进行优化。哈希索引不适合范围查询,哈希索引只支持单字段的索引,不支持多字段索引。

         新建哈希索引:db.collection.ensureIndex({"createTime":"hashed"});

   8、后台索引

        db.people.ensureIndex({zipcode:1},{background:true})

         后台索引不会像其它索引一样,不是个阻塞操作。

   9、稀疏索引   { sparse: true }

    稀疏索引的特点:如果针对field做索引,针对不含field列的文档将不建立索引。

 

#准备数据
db.user2.insert({'name':'zhangsan'});
db.user2.insert({'name':'lisi'});
db.user2.insert({});

db.user2.find({'name':null});

#唯一索引测试
db.user2.ensureIndex({"name":1},{unique: true})
db.user2.find({'name':null}).explain();  #使用了索引
db.user2.find({'name':'zhangsan'}).explain(); #使用了索引
db.user2.dropIndexes();


db.user2.ensureIndex({"name":1},{sparse: true})
db.user2.find({'name':null}).explain();  #没有使用索引
db.user2.find({'name':'zhangsan'}).explain(); #使用了索引

    注意:db.user2.find({'name':null}).explain();  #没有使用索引,这是稀疏索引和其它索引的区别

 

   10、地理位置坐标索引

       xxxxxx

 

 

 参考文章:http://www.jb51.net/article/39671.htm

                   http://www.cnblogs.com/Amaranthus/p/3574058.html#_Toc381385679

三、建立索引的原则

 

   1、创建的索引要匹配查询

如果你仅仅要查询单个字段。索引这个字段即可。如
db.user.find({"account":"zhangsan"})
这个例子中,唯一索引是最佳的
db.user.ensureIndex({"account":1 }, {unique: true});

   

然而,一般都查询多个键并且排序结果。这种情况,组合索引是最佳的,例子如下
db.project_material.find({ provinceId : '66ef8bd44b3a4a8d6a819120'}).sort({ createTime : -1 });
创建的索引如下
db.project_material.ensureIndex({provinceId : 1, createTime : -1});

 

2、索引列颗粒越小越好

 

3、要小心单键索引的低选择性。

 

4、要关注应用读/写( read/write) 比率,不要随意添加索引

这个很重要,因为,添加索引意味着添加,更新,删除操作变慢。

如果你的应用是偏向于读取,使用索引是非常好的事情。

 

5、先后顺序不一样,效果也不一样

db.item_file.ensureIndex({"displayOrder":1,"itemTitle":1,"itemCode":1});不等于下面的

db.item_file.ensureIndex({"itemTitle":1,"itemCode":1,"displayOrder":1});

 

 

 

参考文章:http://www.2cto.com/os/201501/369209.html

 

索引如何设计(读取场景相应的索引设计)

1,查询返回某些字段,而这些字段都可以放在索引中时

  索引覆盖查询,

  这样做的好处是MongoDB就没有必要加载整个文档,通过索引就可以搞定。

2,联合查询

   支持前缀索引查询。

MongoDB有个特性:不是前缀查询无法利用索引。

3,查询返回数据占文档集合数据的比重很大时

   不建立索引查询会更快。

   比如文档200G  索引50G

   使用索引就必须加载到内存250G,如果不使用索引全表扫描 加载到内存只有200G 反而更快。

4,不要到处使用索引,索引的使用要适中。

返回数据量小的文档,建议使用索引。

返回>=50%文档数据时,不建议使用索引

 

 

四、性能比较

已建立索引和未建索引前后插入效率对比:

var start =new Date();
for(var i=0;i<100000;i++){
	db.log_login_copy1.insert({"user":"ceshi"+i,"fromIP":"113.91.248.225","memo" : "成功登录","logLevel" : "INFO","logModel" : "浏览器"+i});
}
var end = new Date();
print("建了索引插入10万行数据耗时="+(end-start));

 
MongoDB 索引(Index)
            
    
    博客分类: mongodb MongoDB 索引Index 
 

 

var start =new Date();
for(var i=0;i<100000;i++){
	db.log_login_copy2.insert({"user":"ceshi"+i,"fromIP":"113.91.248.225","memo" : "成功登录","logLevel" : "INFO","logModel" : "浏览器"+i});
}
var end = new Date();
print("没建索引插入10万行数据耗时="+(end-start));

 
MongoDB 索引(Index)
            
    
    博客分类: mongodb MongoDB 索引Index 
 

总结:

插入的速度没有网上说的那么快只要三秒左右,为什么呢?

已经建立索引和未建立索引的查询效率差异不大 实际是这样吗?

 

已建立索引和未建索引前后查询效率对比:

查询语句

db.log_login.find({"user":"qinghai"}).explain()

 

建立索引的语句

db.log_login.ensureIndex({"user":1})

  

 没有建立索引查询耗时(总共100万行记录):
MongoDB 索引(Index)
            
    
    博客分类: mongodb MongoDB 索引Index 

 

建立索引后查询耗时(总共100万行记录):
MongoDB 索引(Index)
            
    
    博客分类: mongodb MongoDB 索引Index 

 

 

explain用法: 查看查询计划

  explain()是非常有用的工具,会帮助你获得查询方面诸多有用的信息。只要对游标调用该方法,就可以得到查询细节

  eg:db.role.find().explain()

 

 字段说明:
    cursor:返回游标类型,有BasicCursor和BtreeCursor,后者意味着使用了索引。
    nscanned:扫描document的行数。
    n:返回的文档行数。
    millis:耗时(毫秒)。这个对于比较索引和非索引性能非常有用。
indexBounds:所用的索引。

 


 总结:从上面两幅截图对比可以看出创建索引后速度提升了上百倍

 

问题:

模糊查询为什么使用了索引效率还是非常低下呢?201604  查询用了指定新建的索引后效率至少降低了一半,有什么解决方法吗?   是优化模糊查询的方式解决,还是建立其它索引的方式解决,还是没有解决方法呢?

 

常见错误:

1,Btree::insert: key too large to index 内容太多不能新建索引。

解决方法:在当前数据库下执行下面命令:db.adminCommand({setParameter:true,failIndexKeyTooLong:false});

 

 2,如果执行查询报下面错误

com.mongodb.MongoException: Runner error: Overflow sort stage buffered data usage of 33555102 bytes exceeds internal limit of 33554432 bytes

那提取出查询语句:

db.item_file.find({ "itemTitle" : { "$regex" : "^.*?.*$" , "$options" : "i"} , "itemCode" : { "$regex" : "^.*?.*$" , "$options" : "i"}}).sort({ "displayOrder" : 1}).skip(58860).limit(10);

新建下面索引:

db.item_file.ensureIndex({"displayOrder":1});

但是为什么不是新建下面的索引呢? 20160321.  后面有时间的时候查查。

db.item_file.ensureIndex({"itemTitle":1,"itemCode":1,"displayOrder":1});

新建下面这个索引是可以的。

db.item_file.ensureIndex({"displayOrder":1,"itemTitle":1,"itemCode":1});

 

 

 

 

 

 

 

  

  • MongoDB 索引(Index)
            
    
    博客分类: mongodb MongoDB 索引Index 
  • 大小: 6.5 KB
  • MongoDB 索引(Index)
            
    
    博客分类: mongodb MongoDB 索引Index 
  • 大小: 6.6 KB
  • MongoDB 索引(Index)
            
    
    博客分类: mongodb MongoDB 索引Index 
  • 大小: 25.8 KB
  • MongoDB 索引(Index)
            
    
    博客分类: mongodb MongoDB 索引Index 
  • 大小: 28.7 KB