索引
概述
在本指南中,您可以了解如何使用MongoDB .NET/C#驱动程序使用索引。索引可以提高查询效率,并为查询和存储文档添加功能。
没有索引,MongoDB必须扫描集合中的每个文档以找到与每个查询匹配的文档。这些集合扫描很慢,可能会对应用程序的性能产生负面影响。但是,如果查询存在适当的索引,MongoDB可以使用该索引来限制必须检查的文档。
查询覆盖率和性能
当您对MongoDB执行查询时,您的查询可以包含各种元素
查询条件,指定您正在寻找的字段和值
影响查询执行选项,例如读取关注点
投影条件,指定MongoDB返回的字段
排序条件,指定从MongoDB返回的文档的顺序
当查询、投影和排序中指定的所有字段都在同一个索引中时,MongoDB直接从该索引返回结果,也称为覆盖查询。
有关确保索引覆盖查询条件和投影的更多信息,请参阅覆盖查询部分,位于MongoDB服务器手册中。
运行注意事项
为了提高查询性能,在查询和操作中经常出现的字段以及返回排序结果的字段上建立索引。添加的每个索引在活动时都会消耗磁盘空间和内存,因此可能需要跟踪索引内存和磁盘使用情况以进行容量规划。此外,当写入操作更新索引字段时,MongoDB还会更新相关索引。
由于MongoDB支持动态模式,因此应用程序可以查询名称事先未知或任意的字段。MongoDB 4.2 引入了通配符索引来帮助支持这些查询。通配符索引不是用来替代基于工作负载的索引规划的。
索引类型
MongoDB提供几种不同的索引类型来支持查询数据。以下各节描述最常用的索引类型,并为创建每种索引类型提供示例代码。
注意
以下示例使用的是sample_mflix.movies
和sample_mflix.theaters
集合,这些集合来自Atlas示例数据集。要了解如何创建免费的MongoDB Atlas集群并加载示例数据集,请参阅快速入门.
单字段索引
单字段索引 是指在集合文档的单个字段上具有引用的索引。它们提高了单个字段查询和排序的性能,并支持 TTL 索引,这些索引在指定时间或特定时钟时间后自动从集合中删除文档。
注意
_id
索引是单字段索引的一个示例。当创建新集合时,此索引会自动在 _id
字段上创建。
以下示例在 sample_mflix.movies
集合中的 title
字段上创建一个升序索引
var indexModel = new CreateIndexModel<Movie>(Builders<Movie>.IndexKeys.Ascending(m => m.Title)); collection.Indexes.CreateOne(indexModel);
以下是一个查询示例,该查询受前面代码段中创建的索引的保护
// Define query parameters var filter = Builders<Movie>.Filter.Eq(m => m.Title, "Batman"); var sort = Builders<Movie>.Sort.Ascending(m => m.Title); var projection = Builders<Movie>.Projection.Include(m => m.Title).Exclude(m => m.Id); // Execute query var results = collection.Find(filter).Sort(sort).Project(projection);
有关更多信息,请参阅服务器手册中的 单字段索引。
复合索引
复合索引 包含对集合文档中多个字段的引用,提高了查询和排序性能。
以下示例在 sample_mflix.movies
集合中的 type
和 rated
字段上创建一个复合索引
var indexModel = new CreateIndexModel<Movie>(Builders<Movie>.IndexKeys .Ascending(m => m.Type) .Ascending(m => m.Rated)); collection.Indexes.CreateOne(indexModel);
以下是一个查询示例,该查询受前面代码段中创建的索引的保护
// Define query parameters var typeFilter = Builders<Movie>.Filter.Eq(m => m.Type, "movie"); var ratedFilter = Builders<Movie>.Filter.Eq(m => m.Rated, "G"); var filter = Builders<Movie>.Filter.And(typeFilter, ratedFilter); var sort = Builders<Movie>.Sort.Ascending(m => m.Type).Ascending(m => m.Rated); var projection = Builders<Movie>.Projection .Include(m => m.Type) .Include(m => m.Rated) .Exclude(m => m.Id); // Execute query var results = collection.Find(filter).Sort(sort).Project(projection);
有关更多信息,请参阅服务器手册中的 复合索引。
多键索引
多键索引 从包含数组值的字段中收集和排序数据。您可以使用与单个字段或组合索引相同的语法定义多键索引。
以下示例在sample_mflix.movies
集合中的rated
、genres
(字符串数组)和title
字段上创建了一个组合的多键索引
var indexModel = new CreateIndexModel<Movie>(Builders<Movie>.IndexKeys .Ascending(m => m.Rated) .Ascending(m => m.Genres) .Ascending(m => m.Title)); collection.Indexes.CreateOne(indexModel);
以下是一个查询示例,该查询受前面代码段中创建的索引的保护
// Define query parameters var genreFilter = Builders<Movie>.Filter.AnyEq(m => m.Genres, "Animation"); var ratedFilter = Builders<Movie>.Filter.Eq(m => m.Rated, "G"); var filter = Builders<Movie>.Filter.And(genreFilter, ratedFilter); var sort = Builders<Movie>.Sort.Ascending(m => m.Title); var projection = Builders<Movie>.Projection .Include(m => m.Title) .Include(m => m.Rated) .Exclude(m => m.Id); // Execute query var results = collection.Find(filter).Sort(sort).Project(projection);
多键索引在查询覆盖、索引边界计算和排序行为方面与其他索引的表现不同。有关多键索引的更多信息,包括对其行为和限制的讨论,请参阅服务器手册中的多键索引页面。
聚集索引
聚集索引 指示集合按照键值顺序存储文档。要创建聚集索引,在创建集合时,指定_id
字段作为键,并将Unique
属性设置为true
。一个集合只能包含一个聚集索引。如果您想创建聚集索引,则必须在创建集合时指定。
以下示例在创建新的sample_mflix.reviews
集合时在_id
字段上创建了一个聚集索引
var database = mongoClient.GetDatabase("sample_mflix"); var clusteredIndexOptions = new ClusteredIndexOptions<Review> { Key = Builders<Review>.IndexKeys.Ascending(r => r.Id), Unique = true }; database.CreateCollection("reviews", new CreateCollectionOptions<Review> { ClusteredIndex = clusteredIndexOptions });
要了解更多信息,请参阅服务器手册中的Clustered Indexes和Clustered Collections部分,链接如下:Clustered Indexes和Clustered Collections。
Atlas Search 索引
Atlas Search 功能使您能够在MongoDB Atlas上托管的集合中执行全文搜索。索引指定了搜索的行为以及哪些字段要索引。
要了解有关MongoDB Atlas Search的更多信息,请参阅Atlas Search 索引文档。
注意
Atlas Search 索引管理方法异步运行。驱动方法可以在确认它们成功运行之前返回。要确定索引的当前状态,请调用IMongoSearchIndexManager.List()方法。
以下部分包含链接到教程,展示了如何创建和交互Atlas Search索引。
创建搜索索引
在您可以对Atlas集合进行搜索之前,您必须首先在该集合上创建Atlas Search索引。有关如何使用.NET/C#驱动程序创建Atlas Search索引的说明,请参阅Atlas手册中的创建Atlas搜索索引,并在语言下拉菜单中选择C#。
列出搜索索引
有关如何使用.NET/C#驱动程序查看Atlas Search索引列表的说明,请参阅Atlas手册中的查看Atlas搜索索引,并在语言下拉菜单中选择C#。
更新搜索索引
要了解如何使用.NET/C#驱动程序修改现有的Atlas Search索引,请参阅Atlas手册中的编辑Atlas Search索引,并在语言下拉菜单中选择C#。
删除搜索索引
要了解如何使用.NET/C#驱动程序删除Atlas Search索引,请参阅Atlas手册中的删除Atlas Search索引,并在语言下拉菜单中选择C#。
文本索引
文本索引支持对字符串内容的文本搜索查询。这些索引可以包括任何值是字符串或字符串元素数组的字段。MongoDB支持多种语言的文本搜索。您可以在创建索引时指定默认语言作为选项。
提示
MongoDB提供了一种改进的全文搜索解决方案,即Atlas Search。要了解更多关于Atlas Search索引及其使用方法,请参阅本指南的Atlas Search索引部分。
请注意,文本索引无法支持Atlas Search查询,而Atlas Search索引无法支持文本查询。
单字段
以下示例在sample_mflix.movies
集合中的plot
字段上创建文本索引
var indexModel = new CreateIndexModel<Movie>(Builders<Movie>.IndexKeys.Text(m => m.Plot)); collection.Indexes.CreateOne(indexModel);
以下查询使用了前面代码片段中创建的文本索引
// Define query parameters var filter = Builders<Movie>.Filter.Text("java coffee shop"); var projection = Builders<Movie>.Projection.Include(m => m.Plot).Exclude(m => m.Id); // Execute query var results = collection.Find(filter).Project(projection);
多字段
集合只能包含一个文本索引。如果您想为多个文本字段创建文本索引,则必须创建复合索引。文本搜索在复合索引中的所有文本字段上运行。
以下代码片段在sample_mflix.movies
集合中的title
和genre
字段上创建复合文本索引
var indexModel = new CreateIndexModel<Movie>(Builders<Movie>.IndexKeys .Text(m => m.Title) .Text(m => m.Genre)); collection.Indexes.CreateOne(indexModel);
地理空间索引
MongoDB支持使用2dsphere索引查询地理空间坐标数据。使用2dsphere索引,您可以查询地理空间数据是否包含、相交或接近。
要创建2dsphere索引,您必须指定一个仅包含GeoJSON对象的字段。有关此类型的更多详细信息,请参阅MongoDB服务器手册中的GeoJSON对象。
以下示例文档中sample_mflix.theaters
集合的location.geo
字段是一个GeoJSON点对象,用于描述剧院的坐标
{ "_id" : ObjectId("59a47286cfa9a3a73e51e75c"), "theaterId" : 104, "location" : { "address" : { "street1" : "5000 W 147th St", "city" : "Hawthorne", "state" : "CA", "zipcode" : "90250" }, "geo" : { "type" : "Point", "coordinates" : [ -118.36559, 33.897167 ] } } }
以下示例在location.geo
字段上创建一个2dsphere
索引
重要
尝试在已由地理空间索引覆盖的字段上创建地理空间索引会导致错误。
var indexModel = new CreateIndexModel<Theater>(Builders<Theater>.IndexKeys.Geo2DSphere(t => t.Location.Geo)); collection.Indexes.CreateOne(indexModel);
以下是一个使用"location.geo"索引的地理空间查询示例
// Stores the coordinates of the NY MongoDB headquarters var refPoint = GeoJson.Point(GeoJson.Position(-73.98456, 40.7612)); // Creates a filter to match documents that represent locations up to 1000 meters from the specified point directly from the geospatial index var filter = Builders<Theater>.Filter.Near(m => m.Location.Geo, refPoint, 1000.0, 0.0); // Execute the query var results = collection.Find(filter);
MongoDB还支持用于在欧几里得平面上计算距离和用于处理MongoDB 2.2及以前版本中使用的“旧坐标对”语法的2d
索引。有关更多信息,请参阅服务器手册中的地理空间查询。
唯一索引
唯一索引 确保索引字段不存储重复值。默认情况下,MongoDB 在创建集合时会为 _id
字段创建唯一索引。要创建唯一索引,指定您希望防止重复的字段,并将 Unique
选项设置为 true
。
以下示例在 sample_mflix.theaters
集合中的 theaterId
字段上创建了一个唯一的降序索引。
var options = new CreateIndexOptions { Unique = true }; var indexModel = new CreateIndexModel<Theater>(Builders<Theater>.IndexKeys.Descending(t => t.TheaterId), options); collection.Indexes.CreateOne(indexModel);
如果您尝试执行一个写入操作,该操作存储了违反唯一索引的重复值,MongoDB 将抛出一个类似于以下错误
E11000 duplicate key error index
有关更多信息,请参阅服务器手册中的 唯一索引。
通配符索引
通配符索引 允许对未知或任意字段进行查询。如果您使用的是动态模式,这些索引可能非常有用。
以下示例在 sample_mflix.theaters
集合中所有 location
字段的值上创建了一个升序通配符索引,包括嵌套在子文档和数组中的值。
var indexModel = new CreateIndexModel<Theater>(Builders<Theater>.IndexKeys.Wildcard(t => t.Location)); collection.Indexes.CreateOne(indexModel);
有关更多信息,请参阅服务器手册中的 通配符索引 页面。
列表索引
您可以使用列表(List())方法来检索集合中的索引列表。
以下示例使用列表(List())
方法列出集合中的所有索引
var indexes = collection.Indexes.List(); foreach (var index in indexes.ToList()) { Console.WriteLine(index); }