Mongodb索引

MongoDB中的索引(Indexes)是为了加速查询而创建的数据结构。MongoDB的索引与关系数据库的索引类似,可以显著提高读取操作的性能。

mongodb中的索引概念

  • 默认索引:MongoDB在每个集合上都会自动创建一个包含_id字段的唯一索引。
  • 自定义索引:可以根据查询需要在单个或多个字段上创建索引。

索引类型

单字段索引:在单个字段上创建索引。

db.collection.createIndex({ field: 1 })  // 1表示升序

复合索引:在多个字段上创建索引,字段的顺序很重要。

db.collection.createIndex({ field1: 1, field2: -1 })  // field1升序,field2降序

多键索引(Multikey Index):用于数组字段的索引,每个数组元素都被索引。

db.collection.createIndex({ arrayField: 1 })

文本索引(Text Index):用于文本搜索,支持对字符串内容的全文搜索。

db.collection.createIndex({ field: "text" })

哈希索引(Hashed Index):对字段值进行哈希计算,用于分片键。

db.collection.createIndex({ field: "hashed" })

地理空间索引(Geospatial Index):用于地理位置数据,支持2d和2dsphere索引。

db.collection.createIndex({ location: "2dsphere" })  // 对GeoJSON数据使用

唯一索引(Unique Index):确保索引字段的值唯一。

db.collection.createIndex({ field: 1 }, { unique: true })

部分索引(Partial Index):只索引集合中符合指定条件的文档。

db.collection.createIndex({ field: 1 }, { partialFilterExpression: { status: "active" } })

稀疏索引(Sparse Index):只索引那些包含索引字段的文档。

db.collection.createIndex({ field: 1 }, { sparse: true })

TTL索引(Time-to-Live):自动删除过期的文档,只能用于日期字段。

db.collection.createIndex(
   { "field": 1 },
   { expireAfterSeconds: <seconds> }
)


# 30天后过期
db.logs.createIndex(
   { "create_time": 1 },
   { expireAfterSeconds: 30 * 24 * 60 * 60 }  // 30天的秒数
)

索引操作

查看索引

db.collection.getIndexes()

删除索引

db.collection.dropIndex("index_name")

删除所有索引

db.collection.dropIndexes()

索引优化器

  • 查询优化器(Query Optimizer):MongoDB查询优化器会根据查询条件选择最优的索引。
  • Explain Plan:可以使用explain()方法查看查询的执行计划和使用的索引。
    db.collection.find({ field: value }).explain("executionStats")
    

    查询结果和结果说明

    {
        "explainVersion": "1",                    	    // 显示explain命令的版本
        "queryPlanner": {							    // 包含关于查询计划的信息
            "namespace": "mydb.test1",				    // 查询的数据库和集合
            "indexFilterSet": false,				    // 表示是否有索引过滤器应用, false 表示没有应用索引过滤器
            "parsedQuery": {						    // 表示解析后的查询条件
                "name": {
                    "$eq": "name_99999"
                }
            },
            "queryHash": "A2F868FD",					// 查询的哈希值,用于查询计划缓存
            "planCacheKey": "A3E454E0",					// 查询计划缓存的键
            "maxIndexedOrSolutionsReached": false,		// 是否达到了最大的OR解决方案数量, false 表示未达上限
            "maxIndexedAndSolutionsReached": false,		// 是否达到了最大的AND解决方案数量, false 表示未达上限
            "maxScansToExplodeReached": false,			// 是否达到了扫描的最大数量, false 表示未达上限
            "winningPlan": {							// 表示被选中的查询执行计划
                "stage": "FETCH",						// 当前执行计划的阶段, "FETCH" 表示当前阶段是从索引中获取文档
                "inputStage": {							// 表示输入阶段的计划,通常是索引扫描
                    "stage": "IXSCAN",					// 当前阶段的操作, "IXSCAN" 表示索引扫描
                    "keyPattern": {						// 索引的键模式
                        "name": 1						// 表示在name字段上创建了升序索引
                    },
                    "indexName": "name_1",				// 索引的名称
                    "isMultiKey": false,				// 是否为多键索引, false 表示不是多键索引
                    "multiKeyPaths": {					// 多键索引的路径
                        "name": [ ]						// { "name": [ ] } 表示name字段不是多键索引
                    },
                    "isUnique": false,					// 索引是否唯一, false 表示索引不是唯一的
                    "isSparse": false,					// 索引是否稀疏, false 表示索引不是稀疏的
                    "isPartial": false,					// 索引是否部分索引, false 表示索引不是部分索引
                    "indexVersion": NumberInt("2"),		// 索引版本, 2 表示索引的版本号
                    "direction": "forward",				// 索引扫描的方向, "forward" 表示升序扫描
                    "indexBounds": {					// 索引范围
                        "name": [
                            "[\"name_99999\", \"name_99999\"]"		// 表示查询范围为"name_99999"到"name_99999"
                        ]
                    }
                }
            },
            "rejectedPlans": [ ]						// 被拒绝的计划列表, [] 表示没有被拒绝的计划
        },
        "executionStats": {								// 包含关于查询执行的统计信息
            "executionSuccess": true,					//****** 查询是否成功执行, true 表示成功
            "nReturned": NumberInt("1"),				//****** 返回的文档数量
            "executionTimeMillis": NumberInt("0"),		//****** 查询执行使用了多长时间(毫秒)
            "totalKeysExamined": NumberInt("1"),		// 扫描的索引键总数, 1 表示扫描了1个索引键
            "totalDocsExamined": NumberInt("1"),		//****** 扫描的文档总数, 1 表示扫描了1个文档
            "executionStages": {						// 执行阶段的详细统计信息
                "stage": "FETCH",						// 执行阶段, "FETCH" 表示从索引中提取文档
                "nReturned": NumberInt("1"),			// 从此阶段返回的文档数量, 1 表示返回了1个文档
                "executionTimeMillisEstimate": NumberInt("0"),	// 执行时间的估算值(毫秒)
                "works": NumberInt("2"),				// 当前阶段的工作次数, 2 表示工作了2次
                "advanced": NumberInt("1"),				// 当前阶段的“高级”次数, 1 表示有1次“高级”操作
                "needTime": NumberInt("0"),				// 当前阶段的“需要时间”次数, 0 表示没有“需要时间”操作
                "needYield": NumberInt("0"),			// 当前阶段的“需要让步”次数, 0 表示没有“需要让步”操作
                "saveState": NumberInt("0"),			// 当前阶段的“保存状态”次数, 0 表示没有“保存状态”操作
                "restoreState": NumberInt("0"),			// 当前阶段的“恢复状态”次数, 0 表示没有“恢复状态”操作
                "isEOF": NumberInt("1"),				// 是否到达文件末尾, 1 表示到达文件末尾
                "docsExamined": NumberInt("1"),			// 在此阶段检查的文档数量, 1 表示检查了1个文档
                "alreadyHasObj": NumberInt("0"),		// 已经拥有对象的次数, 0 表示没有“已经拥有对象”的操作
                "inputStage": {							// 输入阶段的详细统计信息(通常是IXSCAN)
                    "stage": "IXSCAN",					// 输入阶段的操作, "IXSCAN" 表示索引扫描
                    "nReturned": NumberInt("1"),		// 从此阶段返回的文档数量, 1 表示返回了1个文档
                    "executionTimeMillisEstimate": NumberInt("0"),	// 执行时间的估算值(毫秒)
                    "works": NumberInt("2"),			// 输入阶段的工作次数, 2 表示工作了2次
                    "advanced": NumberInt("1"),			// 输入阶段的“高级”次数, 1 表示有1次“高级”操作
                    "needTime": NumberInt("0"),			// 输入阶段的“需要时间”次数, 0 表示没有“需要时间”操作
                    "needYield": NumberInt("0"),		// 输入阶段的“需要让步”次数, 0 表示没有“需要让步”操作
                    "saveState": NumberInt("0"),		// 输入阶段的“保存状态”次数, 0 表示没有“保存状态”操作
                    "restoreState": NumberInt("0"),		// 输入阶段的“恢复状态”次数, 0 表示没有“恢复状态”操作
                    "isEOF": NumberInt("1"),			// 是否到达文件末尾, 1 表示到达文件末尾
                    "keyPattern": {						// 索引的键模式
                        "name": 1						// 表示在name字段上创建了升序索引
                    },
                    "indexName": "name_1",				// 索引的名称
                    "isMultiKey": false,				// 是否为多键索引, false 表示不是多键索引
                    "multiKeyPaths": {					// 多键索引的路径
                        "name": [ ]
                    },
                    "isUnique": false,					// 索引是否唯一, false 表示索引不是唯一的
                    "isSparse": false,					// 索引是否稀疏, false 表示索引不是稀疏的
                    "isPartial": false,					// 索引是否部分索引, false 表示索引不是部分索引
                    "indexVersion": NumberInt("2"),		// 索引版本, 2 表示索引的版本号
                    "direction": "forward",				// 索引扫描的方向, "forward" 表示升序扫描
                    "indexBounds": {					// 索引范围
                        "name": [
                            "[\"name_99999\", \"name_99999\"]"
                        ]
                    },
                    "keysExamined": NumberInt("1"),		// 扫描的索引键数量, 1 表示扫描了1个索引键
                    "seeks": NumberInt("1"),			// 索引扫描的次数, 1 表示进行了1次索引扫描
                    "dupsTested": NumberInt("0"),		// 测试的重复记录数, 0 表示没有测试重复记录
                    "dupsDropped": NumberInt("0")		// 丢弃的重复记录数, 0 表示没有丢弃重复记录
                }
            }
        },
        "command": {									// 表示执行的实际命令
            "find": "test1",							// 查询的集合
            "filter": {									// 查询条件
                "name": "name_99999"
            },
            "$db": "mydb"								// 数据库名称
        },
        "serverInfo": {									// 提供关于MongoDB服务器的信息
            "host": "71.xx",							// 服务器的主机名
            "port": NumberInt("27017"),					// 服务器的端口
            "version": "7.0.12",						// MongoDB的版本
            "gitVersion": "b6513ce0781db6818e24619e8a461eae90bc94fc"		// MongoDB的Git版本
        },
        "serverParameters": {							// 显示MongoDB服务器的内部参数, 这些参数通常用于调试和性能调优
            "internalQueryFacetBufferSizeBytes": NumberInt("104857600"),
            "internalQueryFacetMaxOutputDocSizeBytes": NumberInt("104857600"),
            "internalLookupStageIntermediateDocumentMaxSizeBytes": NumberInt("104857600"),
            "internalDocumentSourceGroupMaxMemoryBytes": NumberInt("104857600"),
            "internalQueryMaxBlockingSortMemoryUsageBytes": NumberInt("104857600"),
            "internalQueryProhibitBlockingMergeOnMongoS": NumberInt("0"),
            "internalQueryMaxAddToSetBytes": NumberInt("104857600"),
            "internalDocumentSourceSetWindowFieldsMaxMemoryBytes": NumberInt("104857600"),
            "internalQueryFrameworkControl": "trySbeRestricted"
        },
        "ok": 1											//****** 表示命令是否成功执行, 1 表示成功
    }
    

    stage的选项

1. COLLSCAN(Collection Scan)

  • 说明: 执行全表扫描,逐一检查每个文档,以满足查询条件。
  • 适用场景: 当没有合适的索引时,MongoDB会执行全表扫描。

2. IXSCAN(Index Scan)

  • 说明: 执行索引扫描,使用索引来查找匹配的文档。
  • 适用场景: 当查询可以利用索引加速时,MongoDB会使用索引扫描。

3. FETCH(Fetch)

  • 说明: 从索引中获取文档,并检索实际的文档数据。
  • 适用场景: 通常在IXSCAN之后执行,以从索引中提取实际文档。

4. SORT(Sort)

  • 说明: 对文档进行排序。
  • 适用场景: 当查询结果需要排序时使用。

5. LIMIT(Limit)

  • 说明: 限制返回的文档数量。
  • 适用场景: 当查询包含limit操作符时使用。

6. PROJECT(Project)

  • 说明: 选择返回的字段。
  • 适用场景: 当查询使用projection操作符来指定返回的字段时使用。

7. REDUCE(Reduce)

  • 说明: 对查询结果进行汇总或合并。
  • 适用场景: 通常在某些复杂的聚合操作中出现。

8. MERGE(Merge)

  • 说明: 将多个结果合并为一个结果集。
  • 适用场景: 通常在复合查询或聚合管道中出现。

9. UNWIND(Unwind)

  • 说明: 将数组字段展开为多个文档。
  • 适用场景: 在处理数组字段时使用,特别是在$unwind阶段的聚合管道中。

10. GROUP(Group)

  • 说明: 将文档分组并计算汇总值。
  • 适用场景: 在聚合管道中的$group阶段出现。

11. LOOKUP(Lookup)

  • 说明: 执行集合间的联合操作。
  • 适用场景: 在聚合管道中的$lookup阶段出现。

12. OUT(Out)

  • 说明: 将聚合结果输出到另一个集合。
  • 适用场景: 在聚合管道中的$out阶段出现。

13. INDEXONLY(Index Only)

  • 说明: 查询只使用索引,不需要访问实际的文档。
  • 适用场景: 当查询只需要索引中的字段时使用。

14. SHARD(Shard)

  • 说明: 执行跨分片的查询操作。
  • 适用场景: 在分片集群中,当查询需要跨多个分片时使用。

15. REPARTITION(Repartition)

  • 说明: 对数据进行重新分区。
  • 适用场景: 在某些复杂的聚合管道中可能会出现。

16. PLATFORM(Platform)

  • 说明: 表示使用了某种平台或引擎的特殊执行阶段。
  • 适用场景: 与MongoDB的特定引擎或平台相关的操作。

索引的局限性

  • 写操作开销:索引会增加写操作的开销,因为每次写操作都需要更新索引。
  • 存储空间:索引会占用额外的存储空间,特别是多键索引可能会大幅增加存储需求。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

又逢乱世

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值