抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

摘要:本文学习了什么是索引,索引的创建和删除,以及如何查看索引和分析索引的使用情况。

环境

Windows 10 企业版 LTSC 21H2
MongoDB 6.0.21

1 介绍

索引通常能够极大的提高查询的效率,如果没有使用索引,在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。

这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可能要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

索引是特殊的数据结构,索引存储在易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。

在MongoDB中,常见的索引类型包括:

  • 单属性索引:基于单个属性的索引。
  • 复合索引:基于多个属性组合的索引。
  • 文本索引:用于支持全文搜索。
  • 地理空间索引:用于地理空间数据的查询。
  • 哈希索引:用于对属性值进行哈希处理的索引。

2 创建

2.1 基本语法

语法:

sql
1
2
3
4
5
6
7
8
db.集合名.createIndex(
<keys>,
{
name: <indexName>,
unique: <isUnique>,
hidden: <isHidden>
}
)

含义:

名称 类型 说明
keys 文档 包含属性和值对的文档,其中属性是索引键,值描述该属性的索引类型
indexName 字符串 索引名称,可选,默认使用索引属性的名称和排序顺序来生成索引名称
isUnique 布尔 是否唯一索引,可选,默认为false表示非唯一索引
isHidden 布尔 是否隐藏索引,可选,默认为false表示非隐藏索引,隐藏索引不会参与评估查询计划

2.2 索引类型

2.2.1 单属性索引

单属性索引是在单个属性上创建的索引,适用于查询条件中只涉及该属性的情况。

取值为1时表示升序索引,取值为-1时表示降序索引。

示例:

sql
1
db.student.createIndex({age: 1});

2.2.2 复合索引

复合索引由多个单属性索引组成,适用于查询条件中涉及多个属性的情况。

创建复合索引时,属性的顺序很重要,通常应将最常用且选择性高的属性放在索引的前面。

示例:

sql
1
db.student.createIndex({age: 1, birthDate: 1});

2.2.3 多键索引

多键索引用于数组属性,当属性的值是一个数组时,会自动为数组中的每个元素创建索引键。

示例:

sql
1
db.student.createIndex({scores: 1});

2.2.4 文本索引

文本索引支持对包含字符串内容的属性进行文本搜索查询。当在字符串内容中搜索特定单词或字符串时,文本索引可以提高性能。

文本索引使用text表示,一个集合只能有一个文本索引,但该索引可以包含多个属性。

示例:

sql
1
db.student.createIndex({intro: "text", desc: "text"});

2.2.5 地理空间索引

地理空间索引用于存储地理位置信息,支持地理空间查询,如查找某个区域内的位置等。

提供两种类型的地理空间索引:

类型 描述 示例
2d 支持在平面上解释几何图形的查询 db.student.createIndex({location: "2d"})
2dsphere 支持解释球体上的几何形状的查询 db.student.createIndex({location: "2dsphere"})

2.2.6 哈希索引

哈希索引适用于基于等值匹配的查询,它将属性值映射到一个哈希值,从而加快等值比较的速度。

哈希索引使用hashed表示。

示例:

sql
1
db.student.createIndex({id: "hashed"});

3 删除

3.1 删除一个索引

语法:

sql
1
db.集合名.dropIndex(<indexName>)

含义:

名称 类型 说明
indexName 字符串 要删除的索引名称

示例:

sql
1
db.student.dropIndex("age_1");

3.2 删除多个索引

语法:

sql
1
db.集合名.dropIndexes(<indexNames>)

含义:

名称 类型 说明
indexNames 数组 多个要删除的索引名称,如果为空会删除全部索引

示例:

sql
1
db.student.dropIndexes(["age_1", "birthDate_1"]);

注意:
不能删除_id属性索引,该索引是系统默认创建的,无法删除,只能删除非_id属性的索引。

3.3 设置隐藏索引

可以在不实际删除索引的情况下评估删除索引的潜在影响。

语法:

sql
1
db.集合名.hideIndex(<indexName>)

含义:

名称 类型 说明
indexName 字符串 要设置隐藏的索引名称

示例:

sql
1
db.student.hideIndex("age_1");

3.4 解除隐藏索引

语法:

sql
1
db.集合名.unhideIndex(<indexName>)

含义:

名称 类型 说明
indexName 字符串 要解除隐藏的索引名称

示例:

sql
1
db.student.unhideIndex("age_1");

4 查看

语法:

sql
1
db.集合名.getIndexes()

示例:

sql
1
db.student.getIndexes();

5 分析

5.1 分析计划

使用explain()方法可以获取计划信息。

语法:

sql
1
2
db.集合名.find()
.explain(<verbosity>)

含义:

名称 类型 说明
verbosity 字符串 指定分析返回信息的详细模式,可选,详细模式支持三种:
  • queryPlanner,返回执行的计划信息(默认)
  • executionStats:返回执行的计划信息以及统计信息
  • allPlansExecution:返回所有的计划信息以及统计信息
为了向后兼容早期版本,设置为false表示返回执行的计划信息,设置为true表示返回所有的计划信息以及统计信息。

在使用索引前分析查询:

sql
1
2
db.student.find({age: {$eq: 25}})
.explain("allPlansExecution");

分析查询部分结果:

sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"queryPlanner": {
"namespace": "school.student",
"winningPlan": {
"stage": "COLLSCAN",
"filter": {
"age": {
"$eq": 25
}
},
"direction": "forward"
},
"rejectedPlans": []
},
"executionStats": {
"nReturned": NumberInt("1"),
"executionTimeMillis": NumberInt("0"),
"totalKeysExamined": NumberInt("0"),
"totalDocsExamined": NumberInt("4"),
"executionStages": {
"stage": "COLLSCAN",
"filter": {
"age": {
"$eq": 25
}
},
"nReturned": NumberInt("1"),
"executionTimeMillisEstimate": NumberInt("0")
},
"allPlansExecution": []
}
}

在使用索引后分析查询:

sql
1
2
3
db.student.createIndex({age: 1});
db.student.find({age: {$eq: 25}})
.explain("allPlansExecution");

分析查询部分结果:

sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"queryPlanner": {
"namespace": "school.student",
"winningPlan": {
"stage": "FETCH",
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"age": 1
},
"indexName": "age_1",
"direction": "forward"
}
},
"rejectedPlans": []
},
"executionStats": {
"nReturned": NumberInt("1"),
"executionTimeMillis": NumberInt("1"),
"totalKeysExamined": NumberInt("1"),
"totalDocsExamined": NumberInt("1"),
"executionStages": {
"stage": "FETCH",
"nReturned": NumberInt("1"),
"executionTimeMillisEstimate": NumberInt("0"),
"inputStage": {
"stage": "IXSCAN"
}
},
"allPlansExecution": []
}
}

分析查询部分说明:

属性 类型 说明
queryPlanner 文档 查询的计划信息
queryPlanner.namespace 字符串 使用数据库和集合指定的命名空间
queryPlanner.winningPlan 文档 最终使用的计划
queryPlanner.winningPlan.stage 字符串 计划的阶段,阶段是对操作的描述
queryPlanner.winningPlan.inputStage 文档 计划的子阶段,为其父阶段提供文档或索引键,如果有一个子阶段,则该属性存在
queryPlanner.winningPlan.inputStages 数组 计划的子阶段数组,为其父阶段提供文档或索引键,如果有多个子阶段,则该属性存在
queryPlanner.rejectedPlans 数组 拒绝的候选计划数组,如果没有其他候选计划,则数组可能为空
executionStats 文档 查询的统计信息,只有设置为executionStatsallPlansExecution才会有此内容
executionStats.nReturned 整型 查询的文档数
executionStats.executionTimeMillis 整型 查询的执行时间,单位是毫秒,包括选择计划和执行计划的总时间
executionStats.totalKeysExamined 整型 扫描的索引键数量
executionStats.totalDocsExamined 整型 扫描的文档数量
executionStats.executionStages 文档 以阶段树的形式详细说明计划的执行情况
executionStats.allPlansExecution 数组 候选计划的部分统计信息,只有设置为allPlansExecution才会有此内容

计划的阶段可选值举例:

说明
FETCH 索引文档,表示查询使用了索引,并且需要从索引中检索文档
IXSCAN 索引扫描,表示查询使用了索引,并且正在扫描索引键
COLLSCAN 集合扫描,表示查询没有使用索引,直接扫描整个集合
LIMIT 应用限制,限制返回的文档数量
SKIP 应用跳过,跳过指定数量的文档
SORT 应用排序,对结果进行排序
COUNT 应用计数,对结果进行计数
PROJECTION 应用投影,返回指定属性
PROJECTION_COVERED 覆盖查询,所有需要的属性都在索引中,不需要回表查询
IDHACK _id属性进行查询
TEXT 处理文本查询
IXHASH 处理散列查询

5.2 指定索引

使用hint()方法可以强制使用指定的索引,或者强制不使用索引扫描集合。

使用这种方式可以跳过选择计划的时间,直接通过索引执行计划,节省了查询时间。

语法:

sql
1
2
db.集合名.find()
.hint(<index>)

含义:

名称 类型 说明
index 字符串或文档 执行查询时强制使用指定的索引,通过索引名称或属性来指定索引

使用索引属性指定索引:

sql
1
2
db.student.find({age: {$eq: 25}})
.hint({"age": 1});

使用索引名称指定索引:

sql
1
2
db.student.find({age: {$eq: 25}})
.hint("age_1");

强制扫描集合,不使用任何索引:

sql
1
2
db.student.find({age: {$eq: 25}})
.hint({$natural : 1});

评论