Skip to content

MongoDB - 索引

索引对于数据库性能至关重要。将它们想象成书本后面的索引:您无需阅读每一页来查找某个主题,而是通过索引查找并直接跳转到正确的页面。类似地,如果没有索引,MongoDB 必须执行全表扫描(Collection Scan)——读取每个文档——才能找到匹配的查询结果。这效率低下,特别是对于大型数据集。

索引是一种特殊的数据结构,它存储集合数据的一小部分有序副本,使 MongoDB 能够更高效地执行查询。

您可以使用 createIndex() 方法在集合上创建索引。您需要指定要索引的字段和排序顺序:1 表示升序,-1 表示降序。

在单个字段上创建索引。

// 在 'users' 集合的 'username' 字段上创建升序索引
db.users.createIndex({ "username": 1 });

在多个字段上创建索引。字段的顺序很重要,应与您常见的查询模式匹配。

// 在 'category'(升序)和 'rating'(降序)上创建复合索引
db.products.createIndex({ "category": 1, "rating": -1 });

createIndex() 方法接受一个可选的 options 文档。以下是一些最常用的选项:

选项类型描述
unique布尔值确保索引字段具有唯一值。如果为 true,MongoDB 将拒绝导致重复的插入或更新操作。默认为 false。
name字符串索引的自定义名称。如果未指定,MongoDB 将根据索引键及其顺序生成名称。
background布尔值已弃用(现在是默认行为)。在现代 MongoDB 版本中,所有前台索引构建都很快。此选项保留是为了兼容性,但没有效果。
partialFilterExpression文档创建部分索引。该索引仅包含与指定过滤表达式匹配的文档,从而节省空间并提高性能。
expireAfterSeconds整数创建 TTL(生存时间)索引。MongoDB 将在指定秒数过后自动从集合中删除文档。仅适用于日期字段。
// 在 'email' 字段上创建唯一命名的索引
db.users.createIndex(
{ "email": 1 },
{ unique: true, name: "unique_email_index" }
);

此方法返回一个文档数组,描述集合上的所有索引。

> db.users.getIndexes()
[
{
"v" : 2,
"key" : { "_id" : 1 },
"name" : "_id_"
},
{
"v" : 2,
"key" : { "email" : 1 },
"unique" : true,
"name" : "unique_email_index"
}
]

您可以通过提供索引的名称或键规范来删除特定索引。推荐的做法是按名称删除。

// 按名称删除索引
db.users.dropIndex("unique_email_index");
// 或者,按键模式删除
db.users.dropIndex({ "email": 1 });

不带参数的 dropIndexes() 方法用于删除集合上所有非 _id 索引。请谨慎使用。

要验证您的查询是否使用了索引,可以将 explain() 方法附加到您的游标。它提供了关于查询执行计划的详细信息。

> db.users.find({ email: "test@example.com" }).explain("executionStats")

在输出中,查找 winningPlan.stage。如果显示 IXSCAN(索引扫描),则表示您的查询使用了索引。如果显示 COLLSCAN(全表扫描),则表示没有使用,您可能需要创建合适的索引。