索引是一种用来快速查询数据的数据结构。B+Tree就是一种常见的数据库索引数据结构,MongoDB采用B+Tree做索引,索引创建在collections上。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.
参考数据结构网站:Data Structure Visualization
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])
#删除集合指定索引
db.col.dropIndex("索引名称")
#删除集合所有索引
db.col.dropIndexes()
在某一个特定的字段上建立索引:mongoDB在ID上建立了唯一的单键索引,所以经常会使用id来进行查询。在索引字段上进行精确匹配、排序以及范围查找都会使用此索引
db.books.createIndex({title:1})
对内嵌文档字段创建索引:
复合索引(Compound Index)
复合索引是多个字段组合而成的索引,其性质和单字段索引类似。但不同的是,复合索引中字段的顺序、字段的升降序对查询性能有直接的影响,因此在设计复合索引时则需要考虑不同的查询场景。
db.books.createIndex({type:1,favCount:1})
在数组的属性上建立索引,针对这个数组的任意值的查询都会定位到这个文档,既多个索引入口或者键值引用同一个文档
准备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})
在移动互联网时代,基于地理位置的检索(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
}
}
})
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的文本索引功能存在诸多限制,而官方并未提供中文分词的功能,这使得该功能的应用场景十分受限。
不同于传统的B-Tree索引,哈希索引使用hash函数来创建索引。在索引字段上进行精确匹配,但不支持范围查询,不支持多键hash;Hash索引上的入口是均匀分布的,在分片集合中非常有用;
db.users.createIndex({username:"hashed"})
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" } )
注意事项:通配符索引不兼容的索引类型或属性
# 通配符索引不能支持以下查询
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" ] }
}])