2015-08-21 3 views
0

У меня есть следующий код возвращение 22,000,000 записей из базы данных довольно быстро:Как читать большой IEnumerable <> быстро

var records = from row in dataContext.LogicalMapTable 
          select 
           new 
           { 
            row.FwId, 
            row.LpDefId, 
            row.FlDefMapID 
           }; 

Этого код после вызова базы данных выше занимает более 60 секунд для запуска:

var cache = new Dictionary<string, int>(); 
foreach (var record in records) 
{ 
    var tempHashCode = record.FirmwareVersionID + "." + record.LogicalParameterDefinitionID; 

    cache.Add(tempHashCode, record.FirmwareLogicalDefinitionMapID); 
} 

return cache; 

Есть ли лучший способ сделать это с улучшением производительности?

+6

Я подозреваю, что фактическое исполнение занимает больше времени, чем вы ожидаете. Поскольку первый оператор является только выражением и на самом деле ничего не выполняет. Как только вы начнете повторять «выражение» в 'foreach()', фактический запрос выполняется на сервере. – Silvermind

+4

Не совсем, кроме поиска другого хеша, чем ваш вычисленный. Реальный вопрос, который вы должны задать, заключается в следующем: действительно ли я * действительно ДЕЙСТВИТЕЛЬНО * нуждается в 22 000 000 элементов в моем кеше? –

+3

366,666 записей в секунду - неплохая скорость для любой РСУБД. Все, что выше 100 000 строк в секунду, быстро. Ваш лучший выбор - читать меньше данных, что бы это ни значило в вашем контексте. – dasblinkenlight

ответ

0

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

var records = (from row in dataContext.LogicalMapTable 
          select 
           new 
           { 
            row.FwId, 
            row.LpDefId, 
            row.FlDefMapID 
           }).ToList(); 

Так это ваш LINQ запрос, который медленно, а вот как вы можете это исправить.

Возможно, вам не нужны записи 22M, сохраненные в памяти. Вещи, которые вы можете попробовать:

  • Разбивка (принять, пропустить)
  • Изменить запросы включают в себя определенные идентификаторы или другие столбцы. Например. Перед select * ..., после select * ... where id in (1,2,3) ...
  • ли большая частью аналитической работы в базе данных, это быстро и не занимает ваше приложение памяти
  • Предпочитают запросы, которые приносят небольшие порции данных быстро. Вы можете запускать несколько из них одновременно, чтобы обновлять различные биты вашего UI.
+0

Как сказал oleski - «Вторая часть вашего кода не медленная, она просто вызывает оценку запроса LINQ, вы можете видеть это, потребляя ваш запрос раньше» [См. Отложенное исполнение] (http://blogs.msdn.com/ b/charlie/archive/2007/12/09/deferred-execution.aspx) для более подробной информации. – learningNew

0

Как уже упоминалось в комментариях, чтение всего списка очень неэффективно.

Основываясь на коде, который вы опубликовали, я предполагаю, что после того, как список загрузится в ваш «Кэш», вы найдете FirmwareLogicalDefinitionMapID с помощью ключа FirmwareVersionID + ». + LogicalParameterDefinitionID;

Мое предложение, чтобы улучшить общую производительность и использование памяти является внедрение фактической кэширования, что-то вроде этого:

public static class CacheHelper 
{ 
    public static readonly object _SyncLock = new object(); 
    public static readonly _MemoryCache = MemoryCache.Default; 

    public static int GetFirmwareLogicalDefinitionMapID(int firmwareVersionID, int logicalParameterDefinitionID) 
    { 
     int result = -1; 

     // Build up the cache key 
     string cacheKey = string.Format("{0}.{1}", firmwareVersionID, logicalParameterDefinitionID); 

     // Check if the object is in the cache already 
     if(_MemoryCache.Countains(cacheKey)) 
     { 
      // It is, so read it and type cast it 
      object cacheObject = _MemoryCache[cacheKey]; 

      if(cacheObject is int) 
      { 
       result = (int)cacheObject; 
      } 
     } 
     else 
     { 
      // The object is not in cache, aquire a sync lock for thread safety   
      lock(_SyncLock) 
      { 
       // Double check that the object hasnt been put into the cache by another thread. 
       if(!_MemoryCache.Countains(cacheKey)) 
       { 
        // Still not there, now Query the database 
        result = (from i in dataContext.LogicalMapTable 
           where i.FwId == firmwareVersionID && i.LpDefId == logicalParameterDefinitionID 
           select i.FlDefMapID).FirstOrDefault(); 

        // Add the results to the cache so that the next operation that asks for this object can read it from ram 
        _MemoryCache.Add(new CacheItem(cacheKey, result), new CacheItemPolicy() { SlidingExpiration = new TimeSpan(0, 5, 0) }); 
       } 
       else 
       { 
        // we lost a concurrency race to read the object from source, its in the cache now so read it from there. 
        object cacheObject = _MemoryCache[cacheKey]; 
        if(cacheObject is int) 
        { 
         result = (int)cacheObject; 
        } 
       } 
      } 
     } 

     // return the results 
     return result; 
    } 
} 

Вы также должны читать на .Net MemoryCache: http://www.codeproject.com/Articles/290935/Using-MemoryCache-in-Net-4-0

Надежда это помогает!

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