mongo 唯一约束索引_Mongodb中Index特性

Mongodb支持多种index类型,这相对于其他Nosql数据库而言具有很大的优势,它的索引类型比较接近SQL数据库,所以开发者在mongodb中使用索引将是非常便捷的。索引最大的作用就是提高query的查询性能,如果没有索引,mongodb需要scan整个collection的所有的documents,并筛选符合条件的document,如果有索引,那么query只需要遍历index中有限个索引条目即可,况且index中的条目是排序的,这对“order by”操作也非常有利。

index是一种特殊的数据结构,它以一种易于“traverse”的形式来保存collection数据集的一小部分数据,index保存了指定field或者多个filed的值,并按照filed值的顺序排序,索引条目(entry)的有序性在“相等比较”、range查询操作中可以支撑较高的性能,mongodb可以根据index的顺序返回result。

事实上,mongodb的索引结构和原理,和普通的数据库索引没什么太大区别,数据结构仍然采用B-TREE(以及变种)。

尽管index可以提升query的性能,不过在创建索引时仍需要兼顾一些其他方面的考虑,如果你的collection已经保存了大量数据,此时创建索引将会导致大量的IO操作(内存,磁盘读写),耗时较长;mongodb提供了2种方式:foreground和background,foreground即前台操作,它会阻塞用户对数据的读写操作直到index构建完毕,即任何需要获取read、write锁的操作都会阻塞,默认情况下为foreground;background即后台模式,不阻塞数据读写操作,独立的后台线程异步构建索引,此时仍然允许对数据的读写操作;其中background比foreground更加耗时。我们可以使用此方法指定:

db..createIndex({useid : 1},{background : true})

同时在构建索引之前,最好检测一下index是否有重复的,或者当前query是否可以被现有的index覆盖,因为重建重复的index不能对提升性能有任何帮助。为了避免性能问题,我们需要在应用启动前通过getIndexes()方法检测相应的索引是否存在,通常我们需要使用单独的代码来创建索引,而不是在application中。如果在构建索引完成之前,mongodb异常退出,那么当mongodb重启时是否继续重建可以通过storage.indexBuildRetry(配置文件参数)或者--nonIndexBuildRetry(命令行参数)来决定,如果mongodb在构建是遇到错误,比如“dumplicate key error”这种无法自主兼容解决的,则会终止并退出进程。

collection.createIndex(new Document("useid",1),new IndexOptions().unique(true));##java代码

collection.createIndex(new Document("userid",1),new IndexOptions().name("idx_useid"));//指定index的别名

我们可以使用dropIndex来删除索引信息:

collection.dropIndex("idx_userid");##使用index name删除

collection.dropIndex(new Document("userid",1));

同时mongodb还提供reIndex命令,可以重建index,它的原理就是先drop索引,然后重新创建索引。

遍历索引:

ListIndexesIterable indexes = collection.listIndexes();

MongoCursor cursor = indexes.iterator();

while (cursor.hasNext()) {

Document index = cursor.next();

}

cursor.close();

mongodb中提供了hint()方法,可以强制query使用指定的索引,这在某些场景下有特殊的作用。此外,mongodb像其他database一样提供了explain()方法,用来检测query对索引的选择情况。此处不再赘言。

一、索引类型

1、_id:每个document都必须有_id字段,如果不指定,mongodb会默认生成;_id字段为内置的“唯一索引”,整个collection中不会存在_id值相同的document,这是mongodb的内部机制,开发者无法改变,也不需要开发者显式的为_id建立索引,当然也无法remove它。通过_id字段来查询document是性能极高的,所以如果尽可能的通过_id查询或者update数据。

2、单字段索引(Single Filed):即对单个filed建立索引,也是常说的“普通索引”;建立索引时可以指定索引数据的order:正序还是倒序。比如:db..createIndex({"score" : 1})表示对score字段创建索引,value值正序存储(1表示正序,-1表示倒序)。

3、组合索引(Compound):对多个filed建立索引,即一个索引entry中包含多个filed值;比如{userid : 1, score : -1}表示对userid和score两个field建立索引,索引条目按照userid正序排列,相同的userid的索引条目再根据score值倒序排列。需要注意组合索引中filed的顺序很重要,需要根据application查询的需要慎重设计,否则可能导致无法使用索引而导致性能低下,这涉及到sort操作问题。

mongodb的一个组合索引最多支持31个字段。

组合索引中字段的组合顺序很重要,这和数据库索引一样,索引的匹配仍然遵循“最左前缀”原则。

索引的存储按照字段值的顺序,比如{useid : 1,score : -1},所有索引条目将首先按照userid正序排列,相同的useid按照score字段值倒序排列;对于单子段索引,字段值的排序方式无论是正序还是倒序,并没有太大影响,因为mongodb可以很简单的来“反转”方向;但是对于组合索引,这种排序方式将直接决定是否支持query的sort操作。上述索引可以支持如下查询:

db.user.find().sort({userid:1})

db.user.find().sort({userid:1,score:-1})

db.user.find().sort({userid:-1,score:1})##排序方向反转

#但不支持

db.user.find().sort({userid:1,score:1})

db.user.find().sort({userid:-1,score:-1})

最左前缀(prefix):索引前缀即必须以一个或者多个字段为开头,比如组合索引{"item" : 1,"location" : 1,"stock": 1},它可以支持query中过滤条件包含:1)item字段 2)item字段和location字段 3)item、location、stock三个字段;如果query过滤条件中不包含item字段将无法使用索引,比如location、stock或者location + stock字段的查询条件。

4、复合键索引(Multikey):对document中的数组字段创建索引,就是“复合键索引”;mongodb将会对数组的每个值创建一个索引条目,但每个条目都引用同一个document。复合键索引允许查询数组中是否包含某个(些)元素;如果创建索引的filed为数组,mongodb会自动创建multikey索引,我们不需要显式指定任何额外的属性。如果已经对某个字段建立了复合键索引,那么此后尝试插入新文档但是此字段不是数组时将会抛出error。不需要需要注意,如果索引包含多个字段时(组合索引),只能有一个字段的值为数组,同时对多个数组字段建立复合键索引将不予支持。

在sharding cluster架构中,复合键所以将不能作为sharding key(分片键),或者说数组字段不能作为分片键;复合键(数组字段参与索引)也不能是hash索引,也不支持“Covered query”,很好理解,因为这在存储层面几乎是无法做到的!!

比如文档:{_id : 1,item: "ABC", ratings: [2, 5, 9]};创建索引{ratings: 1},那么对于此单个document而言,将有3个索引key(索引条目):2、5、9,每个索引key都指向同一个文档。此时我们也许已经了解了mongodb是如何构建复合键索引的数据结构了。

5、地理空间索引(Geospatial):为了支持高效的地址位置数据查询,mongodb提供了2种特殊的索引,2d索引(坐标平面)和2sphere索引(经纬球面),存储数据包括经纬度信息(-180 ~ 180)以及数据表示的几何类型;在目前LBS应用中,通过使用Geo索引,可以实现类似于“附近的人、消息”等功能,我们可以利用现有的地图服务获取位置的经纬度信息,同时配合mongodb Geo索引来完成我们的部分业务应用。不过,mongodb并不是专业的LBS数据库。“2d”和2dsphere两种索引要求的document数据结构是不同的,所以开发者需要注意,我们稍后介绍。

2dsphere:经纬球面,如果数据是球面的位置(球面几何),可以使用此索引,2dsphere索引可以与其他多个字段组合。location的数据结构可以为GeoJSON对象或者为传统的坐标对。【参见GeoJSON】mongodb支持如下几种GeoJSON对象:

1)Point:点

2)LineString:线段

3)Polygon:多边形

4)MultiLineString:多条线段

5)MultiPoint:多点

6)MultiPolygon:多个多变形

7)GeometryCollection

2d:平面坐标,在平面几何(欧几里得几何)中计算距离,我们可以存储一些传统的坐标对,这时就可以使用2d索引,2d索引最多只能与一个其他的字段组合,且2d字段必须做前缀,这与2dsphere是有区别的。不过2d索引是mongodb的旧版特性,在2.6之后,我们可以统一使用2dsphere即可,2d索引可以通过转换成GeoJSON中Point类型。

我们使用Geo索引对坐标数据进行如下类型的查询:

1)包含:可以查询包含(inclusion)在指定的多边形区域内的locations(所对应的documents,或者indexes),使用$geoWithin操作符。2d和2dsphere都支持包含查询。

2)相交(intersection):可以查询与指定的几何体相交的locations,仅支持

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值