MongoDB学习笔记之索引(一)

MongoDB索引

索引是一种用来快速查询数据的数据结构。B+Tree就是一种常见的数据库索引数据结构,MongoDB采用B+Tree做索引,索引创建在collections上。MongoDB不使用索引的查询,先扫描所有的文档,再匹配符合条件的文档。使用索引的查询,通过索引找到文档,使用索引能够极大的提升查询效率。

一、MongoDB索引数据结构

索引数据结构介绍及官方文档

MongoDB官方文档:https://docs.mongodb.com/manual/indexes/

MongoDB indexes use a B-tree data structure.

WiredTiger官方文档:WiredTiger: Tuning page size and compression

WiredTiger maintains a table's data in memory using a data structure called a B-Tree ( B+ Tree to be specific), referring to the nodes of a B-Tree as pages. Internal pages carry only keys. The leaf pages store both keys and values.

MongoDB学习笔记之索引(一)_第1张图片

 参考数据结构网站:Data Structure Visualization

WiredTiger数据文件在磁盘的存储结构

MongoDB学习笔记之索引(一)_第2张图片

 索引的分类

1、按照索引包含的字段数量,可以分为单键索引和组合索引(或复合索引)

2、按照索引字段的类型,可以分为主键索引和非主键索引。

3、按照索引节与物理记录的对应方式来分,可以分为聚簇索引和非聚簇索引,其中聚簇索引是指索引节点上直接包含了数据记录,而后者则仅仅包含一个指向数据记录的指针。

4、按照索引的特性不同,又可以分为唯一索引、稀疏索引、文本索引、地理空间索引等

MongoDB支持各种丰富的索引类型,包括单键索引,复合索引、唯一索引等一些常见的结构,由于采用了灵活可变的文档类型,因此它又同样支持对嵌套字段、数组进行索引。通过建立合适的索引,我们可以极大的提升数据的检索速度。在一些特殊应用场景,MongoDB还支持地理空间索引、文本检索索引、TTL索引等不同的特性

索引的设计原则

1、每个查询原则上都需要创建对应的索引

2、单个索引设计应该考虑满足尽量多的查询

3、索引字段选择及顺序需要考虑查询覆盖率及选择性

4、对于更新及其频繁的字段上缩减索引需要慎重

5、对于数组索引需要慎重考虑未来元素个数

6、对于超长字符串类型字段上慎用B数索引

7、并发更新较高的单个集合上不宜创建过多索引

二、索引的操作

创建索引

创建索引语法格式

db.collection.createIndex(keys,options)

1、key值为你要创建的索引字段,1按照升序创建索引,-1 按降序创建索引

2、可选参数列表如下

Parameter

Type

Description

background

Boolean

建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。

unique

Boolean

建立的索引是否唯一。指定为true创建唯一索引。默认值为false.

name

string

索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。

dropDups

Boolean

3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.

sparse

Boolean

对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.

expireAfterSeconds

integer

指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。

v

index version

索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。

weights

document

索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。

default_language

string

对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语

language_override

string

对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

注意:3.0.0版本前创建索引方法为db.collection.ensureIndex()

#创建索引后台执行
db.values.createIndex({open: 1,close: 1},{backgroud: true})
#创建唯一索引
db.values.createIndex({title:1},{unique:true})

查看索引

#查看索引信息
db.books.getIndexes()
#查看索引键
db.books.getIndexKeys()

查看索引占用空间

db.collection.totalIndexSize([is_detail])
  • is_detail:可选参数,传入除0或false外的任意数据,都会显示该集合中每个索引的大小及总大小。如果传入0或false则只显示该集合中所有索引的总大小。默认值为false

MongoDB学习笔记之索引(一)_第3张图片

 删除索引

#删除集合指定索引
db.col.dropIndex("索引名称")
#删除集合所有索引
db.col.dropIndexes()

索引类型

单键索引(Single Field Indexes)

在某一个特定的字段上建立索引:mongoDB在ID上建立了唯一的单键索引,所以经常会使用id来进行查询。在索引字段上进行精确匹配、排序以及范围查找都会使用此索引

MongoDB学习笔记之索引(一)_第4张图片

db.books.createIndex({title:1})

MongoDB学习笔记之索引(一)_第5张图片

对内嵌文档字段创建索引:

MongoDB学习笔记之索引(一)_第6张图片

 复合索引(Compound Index)

         复合索引是多个字段组合而成的索引,其性质和单字段索引类似。但不同的是,复合索引中字段的顺序、字段的升降序对查询性能有直接的影响,因此在设计复合索引时则需要考虑不同的查询场景。

MongoDB学习笔记之索引(一)_第7张图片

db.books.createIndex({type:1,favCount:1})

MongoDB学习笔记之索引(一)_第8张图片

 多键索引(Multikey Index)

在数组的属性上建立索引,针对这个数组的任意值的查询都会定位到这个文档,既多个索引入口或者键值引用同一个文档

MongoDB学习笔记之索引(一)_第9张图片

准备inventory集合:

db.inventory.insertMany([
    { _id: 5, type: "food", item: "aaa", ratings: [ 5, 8, 9 ]},
    { _id: 6, type: "food", item: "bbb", ratings: [ 5, 8, 9 ]},
    { _id: 7, type: "food", item: "ccc", ratings: [ 5, 8, 9 ]},
    { _id: 8, type: "food", item: "ddd", ratings: [ 5, 8, 9 ]},
    { _id: 9, type: "food", item: "eee", ratings: [ 5, 8, 9 ]}

])

创建多键索引

db.inventory.createIndex({ ratings: 1})

多键索引很容易与复合索引产生混淆,复合索引是对个字段的组合,而多键索引仅仅是在一个字段上出现了多键(multi key)。而实质上,多键索引也可以出现在复合字段上

#创建复合多值索引
db.inventory.createIndex({item:1,ratings:1})

嵌入文档的索引数组:

db.inventory.insertMany([
{
  _id: 1,
  item: "abc",
  stock: [
    { size: "S", color: "red", quantity: 25 },
    { size: "S", color: "blue", quantity: 10 },
    { size: "M", color: "blue", quantity: 50 }
  ]
},
{
  _id: 2,
  item: "def",
  stock: [
    { size: "S", color: "blue", quantity: 20 },
    { size: "M", color: "blue", quantity: 5 },
    { size: "M", color: "black", quantity: 10 },
    { size: "L", color: "red", quantity: 2 }
  ]
},
{
  _id: 3,
  item: "ijk",
  stock: [
    { size: "M", color: "blue", quantity: 15 },
    { size: "L", color: "blue", quantity: 100 },
    { size: "L", color: "red", quantity: 25 }
  ]
}
])

在包含嵌套对象的数组字段上创建多键索引

db.inventory.createIndex({ "stock.size" : 1,"stock.quantity" : 1})

MongoDB学习笔记之索引(一)_第10张图片

 地理空间索引(Geospatial Index)

在移动互联网时代,基于地理位置的检索(LBS)功能几乎是所有应用系统的标配。MongoDB为地理空间检索提供了非常方便的功能。地理空间索引(2dsphereindex)就是专门用于实现位置索引的一种特殊索引。

案例:MongoDB实现查询附近商家:

假设商家的数据模型如下:

db.restaurant.insert({
    restaurantId: 0,
    restaurantName: "兰州牛肉面",
    location:{
        type: "Point",
        coordinates: [ -73.97,40.77]
    }
})

创建一个2dsphere索引

db.restaurant.createIndex({location:"2dsphere"})

查询附近10000米的商家信息

db.restaurant.find({
    location:{
        $near : {
            $geometry:{
                type:"Point",
                coordinates:[-73.88,40.78]
            },
            $maxDistance:10000
        }
    }
})
  • $near查询操作符,用于实现附近商家的检索,返回数据库结果会按距离排序
  • $geometry操作符用于指定一个GeoJSON格式的地理空间对象,type=Point表示地理坐标点,coordinates则是用户当前所在的经纬度位置,$maxDistance限定了最大距离,单位是米。

全文检索(Text Indexes)

MongoDB支持全文检索功能,可通过建立文本索引来实现简易的分词检索。

db.reviews.createIndex({comments:"text"})

$text操作符可以在有text index 的集合上执行文本检索。$text将会使用空格和标点符号作为分隔符对检索字符串进行分词,并且对检索字符串中所有的分词结果进行一个逻辑上的OR操作。全文检索能解决快速文本查找的需求,比如有一个博客文章集合,需要根据博客的内容来快速查询,则可以针对博客内容建立索引。

案例:

数据准备:

db.stores.insert(
    [ 
        { _id: 1, name: "Java Hut", description: "Coffee and cakes" },
        { _id: 2, name: "Burger Buns", description: "Gourmet hamburgers" },
        { _id: 3, name: "Coffee Shop", description: "Just coffee" },
        { _id: 4, name: "Clothes Clothes Clothes", description: "Discount clothing" },
        { _id: 5, name: "Java Shopping", description: "Indonesian goods" }
    ]
)

创建name和description的全文索引

db.stores.createIndex({name:"text",description:"text"})

通过$text操作符来查询数据中心所有包含"coffee","shop","java"列表中任何词语的商店

db,stores.find({$text:{$search:"java coffee shop"}})

MongoDB的文本索引功能存在诸多限制,而官方并未提供中文分词的功能,这使得该功能的应用场景十分受限。

Hash索引(Hashed Indexes)

不同于传统的B-Tree索引,哈希索引使用hash函数来创建索引。在索引字段上进行精确匹配,但不支持范围查询,不支持多键hash;Hash索引上的入口是均匀分布的,在分片集合中非常有用;

db.users.createIndex({username:"hashed"})

通配符索引(Wildcard Indexes)

MongoDB的文档模式是动态变化的,而通配符索引建立在一些不可预知的字段上,以此实现查询的加速。MongoDB 4.2引入通配符索引来支持对未知或任意字段的查询。

案例:(准备商品数据,不同商品属性不一样)

db.products.insert([
    {
      "product_name" : "Spy Coat",
      "product_attributes" : {
        "material" : [ "Tweed", "Wool", "Leather" ],
        "size" : {
          "length" : 72,
          "units" : "inches"
        }
      }
    },
    {
      "product_name" : "Spy Pen",
      "product_attributes" : {
         "colors" : [ "Blue", "Black" ],
         "secret_feature" : {
           "name" : "laser",
           "power" : "1000",
           "units" : "watts",
         }
      }
    },
    {
      "product_name" : "Spy Book"
    }
])

创建通配符索引

db.products.createIndex({"product_attributes.$**":1})

通配符索引可以支持任意单字段查询product_attributes或其嵌入字段:

db.products.find({"product_attributes.size.length" : {$gt : 60}})
db.products.find( { "product_attributes.material" : "Leather" } )
db.products.find( { "product_attributes.secret_feature.name" : "laser" } )

注意事项:通配符索引不兼容的索引类型或属性

MongoDB学习笔记之索引(一)_第11张图片

 MongoDB学习笔记之索引(一)_第12张图片

  • 通配符索引是稀疏的,不索引空字段。因此,通配符索引不能支持查询字段不存在的文档。
# 通配符索引不能支持以下查询
db.products.find( {"product_attributes" : { $exists : false } } )
db.products.aggregate([
  { $match : { "product_attributes" : { $exists : false } } }
])
  • 通配符索引为文档或数组的内容生成条目,而不是文档/数组本身。因此通配符索引不能支持精确的文档/数组相等匹配。通配符索引可以支持查询字段等于空文档{}的情况。
#通配符索引不能支持以下查询:
db.products.find({ "product_attributes.colors" : [ "Blue", "Black" ] } )

db.products.aggregate([{
  $match : { "product_attributes.colors" : [ "Blue", "Black" ] } 
}])

你可能感兴趣的:(MongoDB数据库,docker,mongodb,数据库,java)