2016-06-01 2 views
0

Я столкнулся с проблемами производительности при получении отфильтрованных данных в небольшой локальной базе данных. Я уменьшил код (как показано ниже), чтобы воспроизвести проблему. Выходной сигнал составляет около 2000 мс.MongoDb C# Driver - Получить элемент по индексированному полю очень медленно

Некоторая дополнительная информация:

  • Запрашиваемый коллекция содержит 135000 записей с 7 простых типов каждый
  • При выполнении аналогичного запроса в чем-то вроде RoboMongo - db.TickerData.find ({_ ид : ObjectId ('5731d39062deb83134772e77')}). Explain() - totalExecutionTime is < 1ms
  • Я использую новейшие версии сервера MongoDb и версии C#
  • База данных работает локально (четырехъядерный 16Mb Ram) в той же среде dev/debug
  • Я не заметил разницы в производительности между индексированными и не проиндексированными полями при тестировании в других полях, кроме ID (который всегда индексируется)
  • Мой первый, хотя в том, что операция LINQ Одиночная() возвращает все документы, прежде чем сделать один поиск, но из Google'ing, кажется, что все операции LINQ Транспонирование на стороне сервера MongoDB запросов

Код:

public class UnitTest1 
{ 
    public void TestMethod2() 
    { 
     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     new BaseRepository<TickerData>().GetById("5731d39062deb83134772e77"); 
     sw.Stop(); 
     Debug.Write(sw.Elapsed.TotalMilliseconds); 
    } 
} 

public class BaseRepository<T> : MongoBase where T : BaseEntity 
{ 
    MongoDatabase DataBase { get; set; } 
    protected IQueryable<T> Collection { get; set; } 
    MongoCollection<BsonDocument> mCollection { get; set; } 

    public BaseRepository() 
    { 
     DataBase = Server.GetDatabase("TradingBot"); 
     mCollection = DataBase.GetCollection<BsonDocument>(typeof(T).Name); 
     Collection = mCollection.AsQueryable<T>(); 
    } 

    public T GetById(string ID) 
    { 
     return Collection.Single(i => i.Id.ToString() == ID); 
    } 

} 

Обновление: Рекомендовать в соответствии с @rnofenko (см. Комментарии), сделало огромное улучшение, но все еще кажется способ замедлить работу?

+1

Преобразование типа в 'GetById' выглядит обратным образом, что может помешать использованию индекса. Можете ли вы попробовать 'Collection.Single (i => i.Id == new ObjectId (ID)); вместо этого? – JohnnyHK

+0

Да, вы правы, что моя реализация ToString была неправильной. Однако использование SingleAsync в соответствии с решением @ mofenko в любом случае помешало мне использовать ToString на Id. Таким образом, использование было уже правильным, и его выполнение слишком медленно при 500-600 мс. – Pierre

+0

ОК. [MCVE] (http://stackoverflow.com/help/mcve) действительно поможет здесь, так как я не могу воспроизвести то, что вы видите, и ваш примерный код не является полным. – JohnnyHK

ответ

2

Это сложный момент. Вы вызываете метод расширения Одинокий от System.Linq. Фактически вы загружаете всю коллекцию из БД и выбираете по идентификатору внутри своего приложения.

Вместо этого вы должны использовать MongoDB метод расширения - SingleAsync от MongoDB.Driver.Linq.

public async Task<T> GetById(string id) 
{ 
    return await Collection.SingleAsync(x => x.Id == new ObjectId(id)); 
} 
+0

Хотя это движение в правильном направлении, я все еще не получаю то, на что я надеюсь. Использование, как было предложено, приводит к запросу до 500 мс (все еще далеко от того, что <1 мн других клиентов, таких как RoboMongo, получают запросы к БД). Запрос на 356 000 по 3 полям (с составным индексом) занимает 2500 мс. Это уменьшилось с 17 000 мс до огромного улучшения, но все еще чувствует способ замедлить работу? – Pierre

+1

@JohnnyHK прав относительно ID. Преобразуйте аргумент вместо поля. – rnofenko

+0

В соответствии с ответом на @JohnnyHK выше это уже было исправлено по мере того, как меня заставил новый метод. Поэтому проблема сохраняется. – Pierre

Смежные вопросы