Лучшие практики для индексов mongodb по нескольким полям - PullRequest
0 голосов
/ 09 октября 2018

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

Какое решение?Должен ли я иметь только один индекс для каждого фильтруемого поля?(Я должен проверить, как это работает, но это кажется неправильным.)

1 Ответ

0 голосов
/ 16 октября 2018

Хорошая практика, которую следует учитывать при выполнении любых операций Find, - это индексировать то, что делает ваш Find.

Ваш Find, который вы упомянули выше, скорее всего, выполняет сканирование коллекции, потому что не может найти подходящий индекс для использования из вашей коллекции и должен пройти через всю коллекцию, чтобы удовлетворить запрошенную операцию, поэтому ваша низкая производительность.

Я бы посоветовал перелистать вашу кодовую базу для всех находок по сравнению с вашей коллекцией счетов и установить для них соответствующие индексы.Таким образом, при выполнении операции Find mongodb будет использовать наиболее подходящий индекс для выполнения операции.Он также рекомендует Mongo согласно их Стратегиям индексирования

В вашем сценарии я бы предложил использовать Составной индекс , потому что вы смотрите на несколько полей.Также следите за порядком вашего индекса, Монго будет смотреть на первый элемент в индексе.Я бы посоветовал согласовать ваш порядок запросов с вашей стратегией индексирования, чтобы добиться максимальной производительности.

Если вы пытаетесь избежать необходимости настраивать индекс специально для Find, я предлагаю использовать составной индекс и индексировать только самые распространенные свойства, к которым вы обычно обращаетесь в своей базе кода.Они способны удовлетворить более широкий круг запросов.

...