【问题标题】:Best practices for mongodb indexes on multiple fieldsmongodb 多字段索引的最佳实践
【发布时间】:2018-10-16 19:03:47
【问题描述】:

在 mongodb 中,我有一个特定的集合(发票),在整个应用程序中,我们查询发票并按许多不同的字段进行过滤,如下所示:

public static List<Invoice> FindAll(string userId, Enums.InvoiceType? type = null, string propertyId = null, 
            string tenantId = null, string landlordId = null, string ownerUserId = null, 
            bool? isClosed = null, bool? autoGenerated = null, DateTime? startDate = null, DateTime? endDate = null,
            int? skip = null, int? take = null) {
            var builder = Filter;
            var filters = builder.Eq("UserId", userId.ToObjectId());
            if (type.HasValue)
                filters = filters & builder.Eq("Type", type.Value);
            if (!String.IsNullOrEmpty(propertyId))
                filters = filters & builder.Eq("PropertyId", propertyId.ToObjectId());
            if (!String.IsNullOrEmpty(tenantId))
                filters = filters & builder.Eq("TenantId", tenantId.ToObjectId());
            if (!String.IsNullOrEmpty(landlordId))
                filters = filters & builder.Eq("LandlordId", landlordId.ToObjectId());
            if (!String.IsNullOrEmpty(ownerUserId))
                filters = filters & builder.Eq("OwnerUserId", ownerUserId.ToObjectId());
            if (isClosed.HasValue)
                filters = filters & builder.Eq("IsClosed", isClosed.Value);
            if (autoGenerated.HasValue)
                filters = filters & builder.Eq("AutoGenerated", autoGenerated.Value);
            if (startDate.HasValue)
                filters = filters & builder.Gte("DueDate", startDate.Value);
            if (endDate.HasValue)
                filters = filters & builder.Lte("DueDate", endDate.Value);

            var result = Collection().Find(filters)
                .Sort(Builders<Invoice>.Sort.Descending("DueDate"));
            if (skip.HasValue)
                result.Skip(skip.Value);
            if (take.HasValue)
                result.Limit(take.Value);
            return result.ToList();
        }

因为我们过滤的字段太多,所以我为每个可过滤字段创建了单独的索引:

db.Invoice.ensureIndex( { UserId: 1 } );
db.Invoice.ensureIndex( { Type: 1 } );
db.Invoice.ensureIndex( { PropertyId: 1 } );
db.Invoice.ensureIndex( { TenantId: 1 } );
db.Invoice.ensureIndex( { LandlordId: 1 } );
db.Invoice.ensureIndex( { OwnerUserId: 1 } );
db.Invoice.ensureIndex( { DueDate: 1 } );
db.Invoice.ensureIndex( { AutoGenerated: 1 } );

但是,今天我注意到,当按 UserId、Type 和 TenantId(在一个查询中)进行过滤时,大约需要 750 毫秒。一旦我创建了以下索引:

db.Invoice.ensureIndex( { UserId: 1, Type: 1, TenantId: 1 } );

...查询开始耗时约 15 毫秒。很明显,当查询过滤多个字段(使用多个索引)时,在每个将被过滤的单独字段上创建索引是不高效的。但是,我不可能为将要执行的查询的每个排列创建索引。

解决办法是什么?我应该在每个可过滤字段上只有一个索引吗? (我得测试一下它的性能如何,但它似乎是错误的。)

【问题讨论】:

    标签: c# mongodb mongodb-.net-driver


    【解决方案1】:

    在执行任何 Find 操作时要牢记的一个好习惯是根据您的 Find 正在执行的操作进行索引。

    您上面提到的Find 很可能正在执行集合扫描,因为它无法从您的集合中找到合适的索引来使用,并且必须遍历整个集合以满足您请求的操作,因此为什么您的性能缓慢。

    我的建议是在您的代码库中搜索所有针对您的发票集合的发现,并为它们设置相关索引。这样当Find 操作运行时,mongodb 将使用最合适的索引来满足操作。 Mongo 也根据他们的Indexing Strategies

    推荐了它

    在您的情况下,我建议使用Compound Index,因为您正在查找多个字段。还要注意索引的顺序,mongo 将查看索引中的第一项。我建议将您的查询顺序与您的索引策略相匹配,以获得最佳性能。

    如果您想避免专门为Find 设置索引,我建议使用复合索引,并且只索引您通常在代码库中查询的最常见属性。他们能够满足更广泛的查询。

    【讨论】:

      猜你喜欢
      • 2019-10-19
      • 2016-07-10
      • 1970-01-01
      • 1970-01-01
      • 2011-11-15
      • 2023-04-08
      • 2022-01-22
      • 1970-01-01
      • 2018-10-12
      相关资源
      最近更新 更多