MongoDB-索引Index

索引Index

索引-Index

a) 概述

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

如果查询存在适当的索引,MongoDB可以使用该索引限制必须检查的文档数。

索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排序支持有效的相等匹配和基于范围的查询操作。此外,MongoDB还可以使用索引中的排序返回排序结果。

MongoDB索引使用B树数据结构(确切的说是B-Tree,MySQL是B+Tree)

b) 索引的类型

b.1) 单字段索引

MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index)。

对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。

b.2) 复合索引

MongoDB还支持多个字段的用户定义索引,即复合索引(Compound Index)。

复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由 { userid: 1, score: -1 } 组成,则索引首先按userid正序排序,然在每个userid的值内,再在按score倒序排序。

b.3) 其他索引

地理空间索引(Geospatial Index)、文本索引(Text Indexes)、哈希索引(Hashed Indexes)。

地理空间索引(Geospatial Index)

为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引。

文本索引(Text Indexes)

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

哈希索引(Hashed Indexes)

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

c) 索引的管理操作

c.1) 索引的查看

返回一个集合中的所有索引的数组。

sh 复制代码
db.collection.getIndexes()
sh 复制代码
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "articledb.comment"
        }
]
  • v: version 版本号
  • key: 表示在哪个字段上加上索引
    • 1 表示升序
  • name: 索引的名称,默认是 key+下划线 如_id_
  • ns: namespace 命名空间

默认_id索引:

MongoDB在创建集合的过程中,在 _id 字段上创建一个唯一的索引,默认名字为 id ,该索引可防止客户端插入两个具有相同值的文

档,您不能在_id字段上删除此索引。

注意:该索引是唯一索引,因此值不能重复,即 _id 值不能重复的。在分片集群中,通常使用 _id 作为片键。

c.2) 索引的创建

在集合上创建索引

sh 复制代码
db.collection.createIndex(keys, options)
  • keys: 在哪个字段上加索引

【示例】

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

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

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

sh 复制代码
> db.comment.createIndex({userid:1,nickname:-1})
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 2,
    "numIndexesAfter" : 3,
    "ok" : 1
}

c.3) 索引的移除

可以移除指定的索引,或移除所有索引

sh 复制代码
db.collection.dropIndex(index)
  • index: 指定要删除的索引

【示例】

(一)删除 comment 集合中 userid 字段上的升序索引:

sh 复制代码
> db.comment.dropIndex({userid:1})
{ "nIndexesWas" : 3, "ok" : 1 }

(二)所有索引的移除

sh 复制代码
> db.comment.dropIndexes()
{
    "nIndexesWas" : 2,
    "msg" : "non-_id indexes dropped for collection",
    "ok" : 1
}

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

d) 索引的使用

d.1) 执行计划

分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。

那么,通常,我们想知道,建立的索引是否有效,效果如何,都需要通过执行计划查看。

sh 复制代码
db.collection.find(query,options).explain(options)

【示例】

查看根据userid查询数据的情况:

sh 复制代码
> db.comment.find({userid:"1013"}).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "articledb.comment",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "userid" : {
                "$eq" : "1013"
            }
        },
    	"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" : [
                		"[\"1013\", \"1013\"]"
    				]
    			}
    		}
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "9ef3740277ad",
        "port" : 27017,
        "version" : "4.0.10",
        "gitVersion" : "c389e7f69f637f7a1ac3cc9fae843b635f20b766"
    },
    "ok" : 1
}

关键点看:

  • "stage" : "COLLSCAN", 表示全集合扫描
  • : "stage" : "IXSCAN" ,基于索引的扫描

d.2) 涵盖的查询

Covered Queries

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

sh 复制代码
> db.comment.find({userid:"1003"},{userid:1,_id:0})
> db.comment.find({userid:"1003"},{userid:1,_id:0}).explain()
相关推荐
小溪学编程1 小时前
向量数据库 Milvus 基础实践:从入门到上手
数据库·milvus
数据最前线1 小时前
雪上加霜,Oracle向蓝色巨人最后的阵地发起挑战
数据库·oracle
于眠牧北1 小时前
Charles配置指定域名抓取和雷电模拟器中抓取APP接口配置
数据库·redis·缓存
福娃筱欢2 小时前
57014 canceling statement due to user request(金仓 KingbaseES)
数据库·kingbase·金仓数据库
ClouGence2 小时前
SAP HANA 数据同步遇到长事务,如何兼顾实时性与完整性?
数据库·后端
数据库小学妹2 小时前
数据库管理工具有哪些?2026主流工具分类与选型对照
数据库·数据库管理工具·数据库工具·信创数据库·数据库客户端
bingHHB2 小时前
销售订单同步实战:MES生产领料/补料→金蝶材料出库
数据库·集成测试
yexianglunbai2 小时前
冷备份与热备份的区别详解
数据库
ZhengEnCi2 小时前
SQL 与 NoSQL 本质差异完全指南:从数据模型到选型决策的深度剖析
数据库
龙腾AI白云2 小时前
数字孪生:与人工智能融合的技术图景
大数据·数据库·人工智能·知识图谱