首页 > 解决方案 > C# Azure CosmosDb 和 Mongo - 如何知道 Find 是否命中索引,以及针对这种情况的最佳索引建议是什么?

问题描述

我有一个 ASP.Net Core 3.1 API,它使用 Mongo Driver nuget package v2.11 将文档保存在 Azure CosmosDb 中。

首先,我的文档类:

public class Customer
{
   public Guid CustomerId {get;set;}

   public string Email {get;set;}

   public int Channel {get;set;}

   public string PartitionKey
   {
       get { return GetPartitionKey(CustomerId); }
       set {; }
   }

   public static string GetPartitionKey(Guid id)
   {
       return id.ToString().Substring(0, 2);
   }
}

在分享我的存储库类之前,我想分享一些关于我在这里遇到的情况的细节。我有一个分区集合(具有我的 Customer 类的 PartitionKey 属性),我对 Find 操作有两个要求:

我的问题是关于适当的索引,以便在我通过分区键以外的其他东西找到它们时利用它们。让我们转到存储库类,然后转到索引:

public class MyRepository
{
    private IMongoCollection<Customer> Collection;

public MyRepository()
{
    MongoClientSettings settings = MongoClientSettings.FromUrl(new MongoUrl("The connection string"));
    settings.SslSettings = new SslSettings() { EnabledSslProtocols = SslProtocols.Tls12 };
            
    var mongoClient = new MongoClient(settings);
    var database = mongoClient.GetDatabase("db-customer");
    
    this.Collection = database.GetCollection<Customer>("col-customer");
    
    //  What indexes here ?!?
}

public Customer GetByKey(Guid customerId, int channel)
{
    var channelFilter = Builders<Customer>.Filter.Eq(x => x.Channel, customer.Channel);

    var idFilter = Builders<Customer>.Filter.Eq(x => x.CustomerId, customer.CustomerId);
    
    var filter = channelFilter & idFilter;
    
    Customer result = this.Collection.Find(filter).FirstOrDefault();
    
    return result;
}

public bool Exists(Customer customer)
{
    var channelFilter = Builders<Customer>.Filter.Eq(x => x.Channel, customer.Channel);
    var emailFilter = Builders<Customer>.Filter.Eq(x => x.Email, customer.Email);

    var idFilter = Builders<Customer>.Filter.Eq(x => x.CustomerId, customer.CustomerId);

    var filter = channelFilter & (emailFilter | idFilter);

    bool found =  this.Collection.Find(filter).FirstOrDefault() != null;

    return found;
}
}

所以,我的问题是,这个存储库的最佳索引设置是什么?我是否应该为我正在搜索的每个字段创建一个索引,如下所示:

this.Collection.Indexes.CreateOne(new CreateIndexModel<Customer>(Builders<Customer>.IndexKeys.Ascending(i => i.CustomerId)));
    this.Collection.Indexes.CreateOne(new CreateIndexModel<Customer>(Builders<Customer>.IndexKeys.Ascending(i => i.Channel)));
    this.Collection.Indexes.CreateOne(new CreateIndexModel<Customer>(Builders<Customer>.IndexKeys.Ascending(i => i.Email)));

或者我应该创建复合索引,这取决于我尝试尝试的搜索,像这样?

this.Collection.Indexes.CreateOne(new CreateIndexModel<Customer>(Builders<Customer>.IndexKeys.Ascending(i => i.CustomerId).Ascending(i => i.Channel)));
    this.Collection.Indexes.CreateOne(new CreateIndexModel<Customer>(Builders<Customer>.IndexKeys.Ascending(i => i.CustomerId).Ascending(i => i.Email).Ascending(i => i.Channel)));

通过使用 Azure 监视器检查指标,我总是获得较低的 RU 消耗和整体较短的响应时间,但我的存储库在此阶段有一些记录。恐怕随着记录数量的增加(这将有数百万条记录),RU 消耗变得太大或响应时间太长,或者在最坏的情况下,两者兼而有之。

我可以在这个问题上得到你的两分钱吗?谢谢。

标签: c#mongodbazure-cosmosdb

解决方案


只有当您的查询需要同时对多个字段进行有效排序时,您才应该创建复合索引。对于具有多个不需要排序的过滤器的查询,创建多个单字段索引而不是单个复合索引。一个查询使用多个可用的单字段索引。

因此,就您而言,我看到您有多个不需要排序的过滤器。因此创建多个单字段索引。

有关详细信息,请参阅在 Azure Cosmos DB 的 API for MongoDB 中管理索引


推荐阅读