В mongodb у меня есть определенная коллекция (Invoice), и во всем нашем приложении мы запрашиваем счета и фильтруем по многим различным полям, например, так:
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 мс.Совершенно очевидно, что создание индексов для каждого отдельного поля, которое будет фильтроваться, не будет производительным, если запросы фильтруются по нескольким полям (с использованием нескольких индексов). Однако я не могу создать индексы для каждой перестановки запросов, которые будут выполняться.
Какое решение?Должен ли я иметь только один индекс для каждого фильтруемого поля?(Я должен проверить, как это работает, но это кажется неправильным.)