MongoDB 多键索引
时间:2022-06-06
本文章向大家介绍MongoDB 多键索引,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
在MongoDB中可以基于数组来创建索引。MongoDB为数组每一个元素创建索引值。多键索引支持数组字段的高效查询。多键索引能够基于字符串,数字数组以及嵌套文档进行创建。本文主要描述多键索引并给出演示示例。
一、多键索引
基于一个数组创建索引,MongoDB会自动创建为多键索引,无需刻意指定
多键索引也可以基于内嵌文档来创建
多键索引的边界值的计算依赖于特定的规则
注,多键索引不等于在文档上的多列创建索引(复合索引)
创建语法
db.coll.createIndex( { <field>: < 1 or -1 > } )
复合多键索引
对于一个复合多键索引,每个索引最多可以包含一个数组。
在多于一个数组的情形下来创建复合多键索引不被支持。
假定存在如下集合
{ _id: 1, a: [ 1, 2 ], b: [ 1, 2 ], category: "AB - both arrays" }
不能基于一个基于{ a: 1, b: 1 } 的多键索引,因为a和b都是数组
假定存在如下集合
{ _id: 1, a: [1, 2], b: 1, category: "A array" }
{ _id: 2, a: 1, b: [1, 2], category: "B array" }
则可以基于每一个文档创建一个基于{ a: 1, b: 1 }的复合多键索引
原因是每一个索引的索引字段只有一个数组
一些限制
不能够指定一个多键索引为分片片键索引
哈希索引不能够成为多键索引
多键索引不支持覆盖查询
基于整体查询数组字段
当一个查询筛选器将一个数组作为整体实现精确匹配时,MongoDB可以使用多键索引查找数组的第一个元素,
但不能使用多键索引扫描寻找整个数组。相反,使用多键索引查找查询数组的第一个元素后,MongoDB检索
相关文档并且过滤出那些复合匹配条件的文档。
二、示意图
如下图,基于集合上的数组创建多键索引,且数组为内嵌文档
三、创建多键索引
1、演示环境
> db.version()
3.2.10
>db.inventory.insertMany([
{ _id: 5, type: "food", item: "aaa", ratings: [ 5, 8, 9 ] },
{ _id: 6, type: "food", item: "bbb", ratings: [ 5, 9 ] },
{ _id: 7, type: "food", item: "ccc", ratings: [ 9, 5, 8 ] },
{ _id: 8, type: "food", item: "ddd", ratings: [ 9, 5 ] },
{ _id: 9, type: "food", item: "eee", ratings: [ 5, 9, 5 ] }])
//下面基于ratings列创建一个多键索引
> db.inventory.createIndex( { ratings: 1 } )
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
//查询数组上为5,9的文档
> db.inventory.find( { ratings: [ 5, 9 ] } )
{ "_id" : 6, "type" : "food", "item" : "bbb", "ratings" : [ 5, 9 ] }
//下面查看其执行计划
> db.inventory.find( { ratings: [ 5, 9 ] } ).explain()
{
"queryPlanner" : {
........
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"ratings" : 1
},
"indexName" : "ratings_1",
"isMultiKey" : true, //这里表明查询使用到了多键索引
.......
"direction" : "forward",
"indexBounds" : {
"ratings" : [
"[5.0, 5.0]",
"[[ 5.0, 9.0 ], [ 5.0, 9.0 ]]"
..........
"ok" : 1
}
//在上面的示例中,使用了多键索引进行扫描,MongoDB寻找在ratings数组任意位置包含5的文档
//然后MongoDB检索这些文档,并过滤出那些等于[ 5, 9 ]的文档
2、基本索引数组
假定存在下列集合
{ _id: 1, item: "ABC", ratings: [ 2, 5, 9 ] }
在ratings上创建索引
db.survey.createIndex( { ratings: 1 } )
这个多键索引则包括2,5,9三个索引键,每一个分别指向相同的文档
3、基于内嵌文档的索引数组
//创建演示文档
> db.inventory.drop()
> 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", // Author : Leshami
stock: [ // Blog : http://blog.csdn.net/leshami
{ 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 }
]
}])
//下面基于内嵌文档的2个键来创建索引
> db.inventory.createIndex( { "stock.size": 1, "stock.quantity": 1 } )
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
//查询内嵌文档stock.size为M的执行计划
> db.inventory.find( { "stock.size": "M" } ).explain()
{
"queryPlanner" : {
........
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN", //基于索引的扫描
"keyPattern" : {
"stock.size" : 1,
"stock.quantity" : 1
},
"indexName" : "stock.size_1_stock.quantity_1",
.......
"indexBounds" : {
"stock.size" : [
"["M", "M"]"
],
"stock.quantity" : [
"[MinKey, MaxKey]"
]
}
}
},
}
//基于内嵌文档2个键查询的执行计划
> db.inventory.find( { "stock.size": "S", "stock.quantity": { $gt: 20 } } ).explain()
{
"queryPlanner" : {
..........
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"stock.quantity" : {
"$gt" : 20
}
},
"inputStage" : {
"stage" : "IXSCAN", //此时同样也使用到了索引扫描
"keyPattern" : {
"stock.size" : 1,
"stock.quantity" : 1
},
"indexName" : "stock.size_1_stock.quantity_1",
"isMultiKey" : true,
.........
"indexBounds" : {
"stock.size" : [
"["S", "S"]"
],
"stock.quantity" : [
"[MinKey, MaxKey]"
............
"ok" : 1
}
//基于内嵌数组排序查询
> db.inventory.find( ).sort( { "stock.size": 1, "stock.quantity": 1 } ).explain()
{
"queryPlanner" : {
........
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN", //内嵌数组排序查询也使用到了索引
"keyPattern" : {
"stock.size" : 1,
"stock.quantity" : 1
},
"indexName" : "stock.size_1_stock.quantity_1",
"isMultiKey" : true,
...........
"indexBounds" : {
"stock.size" : [
"[MinKey, MaxKey]"
],
"stock.quantity" : [
"[MinKey, MaxKey]"
]
}
}
},
"rejectedPlans" : [ ]
},
}
//基于内嵌数组一个键作为过滤,一个键作为排序查询的执行计划
> db.inventory.find( { "stock.size": "M" } ).sort( { "stock.quantity": 1 } ).explain()
{
"queryPlanner" : {
..........
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"stock.size" : 1,
"stock.quantity" : 1
},
"indexName" : "stock.size_1_stock.quantity_1",
"isMultiKey" : true,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"stock.size" : [
"["M", "M"]"
],
"stock.quantity" : [
"[MinKey, MaxKey]"
"rejectedPlans" : [ ]
.......
"ok" : 1
}
更多参考 MongoDB 单键(列)索引 MongoDB 复合索引 MongoDB执行计划获取(db.collection.explain())
- go sync.Mutex 设计思想与演化过程 --转
- hadoop开发必读:认识Context类的作用
- Logback+ELK+SpringMVC搭建日志收集服务器
- 【译】Spring 官方教程:创建批处理服务
- Oracle12c R2版本Application Containers特性(三)
- Shell系列-编写及执行脚本
- Spring Security 入门(五):在 Spring-Boot中的应用
- Go语言Goroutine与Channel内存模型
- Tarjan--LCA算法的个人理解即模板
- spark sql编程之实现合并Parquet格式的DataFrame的schema
- Oracle压缩黑科技(一)—基础表压缩
- 12 条用于 Linux 的 MySQL/MariaDB 安全最佳实践
- hdu----(4545)魔法串(LCS)
- Oracle压缩黑科技(二)—压缩数据的修改
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Spring多数据源事务如何玩? | Spring系列46篇
- 使用Mfuzz包做时间序列分析
- 网络安全 | 瑞哥带你全方位解读防火墙技术!
- 【SpringBoot DB 系列】Jooq 之新增记录使用姿势
- 突击并发编程JUC系列-并发工具 Semaphore
- 构建Linux根文件系统
- ARM指令ldr和adr的区别
- 挂载文件系统出现"kernel panic..." 史上最全解决方案
- 汇编程序调用c函数为什么需要设置栈?
- Uboot到底如何启动内核
- Flink部署及作业提交(On YARN)
- Flink部署及作业提交(On Flink Standalone)
- MySQL题集
- 《深入浅出SQL》问答录
- Python_字典实现简单预约系统