zoukankan      html  css  js  c++  java
  • Mongodb的索引

    索引-Index

    1 概述

    索引支持在MongoDB中高效地执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句
    匹配的文档。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非
    常致命的。

    如果查询存在适当的索引,MongoDB可以使用该索引限制必须检查的文档数。
    索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排
    序支持有效的相等匹配和基于范围的查询操作。此外,MongoDB还可以使用索引中的排序返回排序结果。
    官网文档: https://docs.mongodb.com/manual/indexes/
    MongoDB索引使用B树数据结构(确切的说是B-Tree,MySQL是B+Tree)

    2 索引的类型

    2.1 单字段索引

    MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index)。
    对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。

    image-20201012001226622

    2.2 复合索引

    MongoDB还支持多个字段的用户定义索引,即复合索引(Compound Index)。
    复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由 { userid: 1, score: -1 } 组成,则索引首先按userid正序排序,然后
    在每个userid的值内,再在按score倒序排序。

    image-20201012001248449

    2.3 其他索引

    地理空间索引(Geospatial Index)、文本索引(Text Indexes)、哈希索引(Hashed Indexes)。
    地理空间索引(Geospatial Index)
    为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面
    几何的二维球面索引。

    文本索引(Text Indexes)
    MongoDB提供了一种文本索引类型,支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如“the”、“a”、“or”),
    而将集合中的词作为词干,只存储根词。

    哈希索引(Hashed Indexes)
    为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支
    持相等匹配,不支持基于范围的查询。

    3 索引的管理操作

    3.1 索引的查看

    说明:
    返回一个集合中的所有索引的数组。
    语法:
    提示:该语法命令运行要求是 MongoDB 3.0+
    【示例】
    查看comment集合中所有的索引情况

    > db.comment.getIndexes()
    [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]
    
    

    结果中显示的是默认 id 索引。
    默认id索引:
    MongoDB在创建集合的过程中,在 id 字段上创建一个唯一的索引,默认名字为 _id ,该索引可防止客户端插入两个具有相同值的文档,您不能在id字段上删除此索引。
    注意:该索引是唯一索引,因此值不能重复,即 _id 值不能重复的。在分片集群中,通常使用 _id 作为片键。

    3.2 索引的创建

    说明:
    在集合上创建索引。
    语法:

    db.collection.getIndexes()
    

    参数:

    Parameter Type Description
    keys document 包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型。对于字段上的升序索引,请 指定值1;对于降序索引,请指定值-1。比如: {字段:1或-1} ,其中1 为指定按升序创建索引,如果你 想按降序来创建索引指定为 -1 即可。另外,MongoDB支持几种不同的索引类型,包括文本、地理空 间和哈希索引。
    options document 可选。包含一组控制索引创建的选项的文档。有关详细信息,请参见选项详情列表。

    options(更多选项)列表:

    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,默认值为 languag

    提示:
    注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex() ,之后的版本使用了 db.collection.createIndex() 方法,ensureIndex() 还能用,但只是 createIndex() 的别名。

    【示例】
    (1)单字段索引示例:对 userid 字段建立索引:

    > db.comment.createIndex({userid:1})
    {
            "createdCollectionAutomatically" : false,
            "numIndexesBefore" : 1,
            "numIndexesAfter" : 2,
            "ok" : 1
    }
    
    

    参数1:按升序创建索引
    可以查看一下:

    > db.comment.getIndexes()
    [
            {
                    "v" : 2,
                    "key" : {
                            "_id" : 1
                    },
                    "name" : "_id_"
            },
            {
                    "v" : 2,
                    "key" : {
                            "userid" : 1
                    },
                    "name" : "userid_1"
            }
    ]
    >
    
    

    image-20201012003231567

    (2)复合索引:对 userid 和 nickname 同时建立复合(Compound)索引:

    > db.comment.getIndexes()
    [
            {
                    "v" : 2,
                    "key" : {
                            "_id" : 1
                    },
                    "name" : "_id_"
            },
            {
                    "v" : 2,
                    "key" : {
                            "userid" : 1
                    },
                    "name" : "userid_1"
            },
            {
                    "v" : 2,
                    "key" : {
                            "userid" : 1,
                            "nickname" : -1
                    },
                    "name" : "userid_1_nickname_-1"
            }
    ]
    >
    
    

    image-20201012003754815

    3.3 索引的移除

    说明:可以移除指定的索引,或移除所有索引
    一、指定索引的移除
    语法:

    db.collection.dropIndex(index)
    
    arameter Type Description
    index string or document 指定要删除的索引。可以通过索引名称或索引规范文档指定索引。若要删除文本索引,请指定 索引名称。

    【示例】
    删除 comment 集合中 userid 字段上的升序索引:

    > db.comment.dropIndex({userid:1})
    { "nIndexesWas" : 3, "ok" : 1 }
    > db.comment.getIndexes()
    [
            {
                    "v" : 2,
                    "key" : {
                            "_id" : 1
                    },
                    "name" : "_id_"
            },
            {
                    "v" : 2,
                    "key" : {
                            "userid" : 1,
                            "nickname" : -1
                    },
                    "name" : "userid_1_nickname_-1"
            }
    ]
    >
    
    

    二、所有索引的移除
    语法:

    db.collection.dropIndexes()
    

    【示例】
    删除 spit 集合中所有索引。

    > db.comment.dropIndexes()
    {
            "nIndexesWas" : 2,
            "msg" : "non-_id indexes dropped for collection",
            "ok" : 1
    }
    > db.comment.getIndexes()
    [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]
    >
    
    

    提示: _id 的字段的索引是无法删除的,只能删除非 _id 字段的索引。

    4 索引的使用

    4.1 执行计划

    分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是
    否基于索引查询等。
    那么,通常,我们想知道,建立的索引是否有效,效果如何,都需要通过执行计划查看。
    语法:

    db.collection.find(query,options).explain(options)
    

    插入测试数据

    > db.auth("dalianpai","123456")
    1
    > db.comment.insertMany([{"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"}, {"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"}, {"_id":"3","articleid":"100001","content":"我一直喝凉开水,冬天夏天都喝。","userid":"1004","nickname":"杰克船长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"}, {"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"}, {"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}]);
    {
            "acknowledged" : true,
            "insertedIds" : [
                    "1",
                    "2",
                    "3",
                    "4",
                    "5"
            ]
    }
    > db.comment.find()
    { "_id" : ObjectId("5f832d4e65e39f1344b00409"), "articleid" : "100000", "content" : "今天天气真好,阳光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2020-10-11T16:05:34.263Z"), "likenum" : 10, "state" : null }
    { "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("2019-08-05T22:08:15.522Z"), "likenum" : 1000, "state" : "1" }
    { "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 888, "state" : "1" }
    { "_id" : "3", "articleid" : "100001", "content" : "我一直喝凉开水,冬天夏天都喝。", "userid" : "1004", "nickname" : "杰克船长", "createdatetime" : ISODate("2019-08-06T01:05:06.321Z"), "likenum" : 666, "state" : "1" }
    { "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
    { "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("2019-08-06T11:01:02.521Z"), "likenum" : 300, "state" : "1" }
    
    

    【示例】
    查看根据userid查询数据的情况:

    > db.comment.find({userid:"1003"}).explain()
    {
            "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "articledb.comment",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                            "userid" : {
                                    "$eq" : "1003"
                            }
                    },
                    "queryHash" : "37A12FC3",
                    "planCacheKey" : "37A12FC3",
                    "winningPlan" : {
                            "stage" : "COLLSCAN",
                            "filter" : {
                                    "userid" : {
                                            "$eq" : "1003"
                                    }
                            },
                            "direction" : "forward"
                    },
                    "rejectedPlans" : [ ]
            },
            "serverInfo" : {
                    "host" : "3a27b7789865",
                    "port" : 27017,
                    "version" : "4.4.1",
                    "gitVersion" : "ad91a93a5a31e175f5cbf8c69561e788bbc55ce1"
            },
            "ok" : 1
    }
    >
    

    关键点看: "stage" : "COLLSCAN", 表示全集合扫描

    image-20201012004917008

    下面对userid建立索引

    > db.comment.createIndex({userid:1})
    {
            "createdCollectionAutomatically" : false,
            "numIndexesBefore" : 1,
            "numIndexesAfter" : 2,
            "ok" : 1
    }
    
    

    再次查看执行计划:

    > db.comment.find({userid:"1003"}).explain()
    {
            "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "articledb.comment",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                            "userid" : {
                                    "$eq" : "1003"
                            }
                    },
                    "queryHash" : "37A12FC3",
                    "planCacheKey" : "7FDF74EC",
                    "winningPlan" : {
                            "stage" : "FETCH",
                            "inputStage" : {
                                    "stage" : "IXSCAN",
                                    "keyPattern" : {
                                            "userid" : 1
                                    },
                                    "indexName" : "userid_1",
                                    "isMultiKey" : false,
                                    "multiKeyPaths" : {
                                            "userid" : [ ]
                                    },
                                    "isUnique" : false,
                                    "isSparse" : false,
                                    "isPartial" : false,
                                    "indexVersion" : 2,
                                    "direction" : "forward",
                                    "indexBounds" : {
                                            "userid" : [
                                                    "["1003", "1003"]"
                                            ]
                                    }
                            }
                    },
                    "rejectedPlans" : [ ]
            },
            "serverInfo" : {
                    "host" : "3a27b7789865",
                    "port" : 27017,
                    "version" : "4.4.1",
                    "gitVersion" : "ad91a93a5a31e175f5cbf8c69561e788bbc55ce1"
            },
            "ok" : 1
    }
    >
    
    

    关键点看: "stage" : "IXSCAN" ,基于索引的扫描
    compass查看:

    image-20201012005125478

    4.2 涵盖的查询

    Covered Queries
    当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存。 这些覆盖的查询可以
    非常有效。

    image-20201012005442124

    > db.comment.find({userid:"1003"},{userid:1,_id:0})
    { "userid" : "1003" }
    { "userid" : "1003" }
    > db.comment.find({userid:"1003"},{userid:1,_id:0}).explain()
    {
            "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "articledb.comment",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                            "userid" : {
                                    "$eq" : "1003"
                            }
                    },
                    "queryHash" : "8177476D",
                    "planCacheKey" : "B632EADC",
                    "winningPlan" : {
                            "stage" : "PROJECTION_COVERED",
                            "transformBy" : {
                                    "userid" : 1,
                                    "_id" : 0
                            },
                            "inputStage" : {
                                    "stage" : "IXSCAN",
                                    "keyPattern" : {
                                            "userid" : 1
                                    },
                                    "indexName" : "userid_1",
                                    "isMultiKey" : false,
                                    "multiKeyPaths" : {
                                            "userid" : [ ]
                                    },
                                    "isUnique" : false,
                                    "isSparse" : false,
                                    "isPartial" : false,
                                    "indexVersion" : 2,
                                    "direction" : "forward",
                                    "indexBounds" : {
                                            "userid" : [
                                                    "["1003", "1003"]"
                                            ]
                                    }
                            }
                    },
                    "rejectedPlans" : [ ]
            },
            "serverInfo" : {
                    "host" : "3a27b7789865",
                    "port" : 27017,
                    "version" : "4.4.1",
                    "gitVersion" : "ad91a93a5a31e175f5cbf8c69561e788bbc55ce1"
            },
            "ok" : 1
    }
    >
    
    

    Compass中:

    image-20201012005819780

  • 相关阅读:
    多测师讲解html _伪类选择器17_高级讲师肖sir
    多测师讲解html _后代选择器16_高级讲师肖sir
    多测师讲解html _组合选择器_高级讲师肖sir
    多测师讲解html _标签选择器14_高级讲师肖sir
    前端 HTML form表单标签 input标签 type属性 重置按钮 reset
    前端 HTML form表单标签 textarea标签 多行文本
    前端 HTML form表单标签 input标签 type属性 file 上传文件
    前端 HTML form表单标签 input标签 type属性 radio 单选框
    前端 HTML form表单标签 input标签 type属性 checkbox 多选框
    前端 HTML form表单目录
  • 原文地址:https://www.cnblogs.com/dalianpai/p/13800581.html
Copyright © 2011-2022 走看看