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())

时间: 2024-09-20 13:36:16

MongoDB 多键索引的相关文章

MongoDB 稀疏(间隙)索引(Sparse Indexes)

稀疏索引(或者称间隙索引)就是只包含有索引字段的文档的条目,即使索引字段包含一个空值.也就是说间隙索引可以跳过那些索引键不存在的文档.因为他并非包含所有的文档,因此称为稀疏索引.与之相对的非稀疏索引或者说普通索引则包含所有的文档以及为那些不包含索引的字段存储null值. 一.间隙索引创建描述 稀疏索引(或者称间隙索引)就是只包含有索引字段的文档的条目,跳过索引键不存在的文档 本文中后面的描述使用间隙索引 创建索引的语法: db.collection.createIndex(keys, optio

MongoDB 单键(列)索引

MongoDB支持基于集合文档上任意列创建索引.缺省情况下,所有的文档的_id列上都存在一个索引.基于业务的需要,可以基于一些重要的查询和操作来创建一些额外的索引.这些索引可以是单列,也可是多列(复合索引),多键索引,地理空间索引,文本索引以及哈希索引等. 本文主要描述在基于文档上的单列来创建索引. 一.创建语法 语法:db.collection.createIndex(keys, options) keys: 一个包含字段和值键值对的文档,指定该键即在该键上创建索引,如{age:1} 创建索引

MongoDB教程之索引介绍_MongoDB

一.索引基础:     MongoDB的索引几乎与传统的关系型数据库一模一样,这其中也包括一些基本的优化技巧.下面是创建索引的命令:   复制代码 代码如下:     > db.test.ensureIndex({"username":1})       可以通过下面的名称查看索引是否已经成功建立:   复制代码 代码如下:     > db.test.getIndexes()       删除索引的命令是:   复制代码 代码如下:     > db.test.dr

MongoDB数据库中索引(index)详解_MongoDB

索引:特殊的数据结构,存储表的数据的一小部分以实现快速查询 优点: 1.大大减少了服务器需要扫描的数据量 2.索引可以帮助服务器避免排序或使用临时表 3.索引可以将随机io转换为顺序io 索引评估:三星(非常好) 一星:索引如果能将相关的记录放置到一起 二星:索引中数据的存储顺序与查找标准中顺序一致 三星:如果索引中包含查询中所需要的全部数据:(覆盖索引) DBA书:关系型数据库索引设计与优化 索引类别: 顺序索引 散列索引:将索引映射至散列桶上,映射是通过散列函数进行的 评估索引的标准: 访问

MongoDB数据库index索引的用法和作用

索引最大的作用就是提高query的查询性能,如果没有索引,mongodb需要scan整个collection的所有的documents,并筛选符合条件的document,如果有索引,那么query只需要遍历index中有限个索引条目即可,况且index中的条目是排序的,这对"order  by"操作也非常有利. 索引:特殊的数据结构,存储表的数据的一小部分以实现快速查询 优点: 1.大大减少了服务器需要扫描的数据量 2.索引可以帮助服务器避免排序或使用临时表 3.索引可以将随机io转换

MongoDB · 特性分析 · 索引原理

为什么需要索引? 当你抱怨MongoDB集合查询效率低的时候,可能你就需要考虑使用索引了,为了方便后续介绍,先科普下MongoDB里的索引机制(同样适用于其他的数据库比如mysql). mongo-9552:PRIMARY> db.person.find() { "_id" : ObjectId("571b5da31b0d530a03b3ce82"), "name" : "jack", "age" :

FAQ系列 | MySQL索引之主键索引

导读 在MySQL里,主键索引和辅助索引分别是什么意思,有什么区别? 上次的分享我们介绍了聚集索引和非聚集索引的区别,本次我们继续介绍主键索引和辅助索引的区别. 1.主键索引 主键索引,简称主键,原文是PRIMARY KEY,由一个或多个列组成,用于唯一性标识数据表中的某一条记录.一个表可以没有主键,但最多只能有一个主键,并且主键值不能包含NULL. 在MySQL中,InnoDB数据表的主键设计我们通常遵循几个原则: 采用一个没有业务用途的自增属性列作为主键: 主键字段值总是不更新,只有新增或者

MySQL中主键索引与聚焦索引之概念的学习教程_Mysql

主键索引 主键索引,简称主键,原文是PRIMARY KEY,由一个或多个列组成,用于唯一性标识数据表中的某一条记录.一个表可以没有主键,但最多只能有一个主键,并且主键值不能包含NULL. 在MySQL中,InnoDB数据表的主键设计我们通常遵循几个原则: 采用一个没有业务用途的自增属性列作为主键: 主键字段值总是不更新,只有新增或者删除两种操作: 不选择会动态更新的类型,比如当前时间戳等. 这么做的好处有几点: 新增数据时,由于主键值是顺序增长的,innodb page发生分裂的概率降低了:可以

删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005 .

原文:删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005 . 删除指定表的所有索引,包括主键索引,唯一索引和普通索引 ,适用于sql server 2005, 使用说明 : 1,先执行脚本,将存储过程创建在数据库中 2,调用方法,以黄金搭档数据库为例 use velcromfm --数据库名, 根据具体项目替换 go declare @tableName varchar(20) set @tableName='menu' --表名 ,根据实际情况替换e