在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 } );
...查询开始耗时约15ms。很明显,当查询在多个字段上进行过滤(使用多个索引)时,在将要过滤的每个单独的字段上创建索引是不起作用的。但是,我不可能为将要执行的查询的每个排列都创建索引。
解决方案是什么?我应该在每个可过滤字段上只有一个索引吗? (我必须进行测试以查看其性能,但这似乎是错误的。)
答案 0 :(得分:0)
进行任何Find
操作时要牢记的一个好习惯是根据您的Find
的操作编制索引。
您上面提到的您的Find
最有可能进行集合扫描,因为它无法从集合中找到合适的索引来使用,并且必须遍历整个集合来满足您的请求操作,因此为什么性能会变慢。
我的建议是针对发票收据拖曳所有查找的代码库,并为其设置相关索引。这样,在Find
操作运行时,mongodb将使用最合适的索引来满足该操作。根据Mongo的Indexing Strategies
在您的情况下,我建议您使用Compound Index,因为您要查找多个字段。还要注意索引的顺序,mongo将查看索引中的第一项。我建议您将查询顺序与索引策略相匹配,以获得最佳性能。
如果要避免为Find
专门设置索引,建议您使用复合索引,并仅对通常在代码库中查询的最常见属性进行索引。他们能够满足更广泛的查询。