2010-03-10 4 views
5

Я использую LinqToSQL для обработки данных из SQL Server, чтобы выгрузить их на сервер iSeries для дальнейшей обработки. More details on that here.Что происходит быстрее? Массив Struct или DataTable

Моя проблема заключается в том, что для обработки этих 350 строк данных требуется около 1,25 минуты. Я все еще пытаюсь расшифровать результаты из SQL Server Profiler, но есть TON запросов, которые запускаются. Вот немного более подробно о том, что я делаю:

using (CarteGraphDataDataContext db = new CarteGraphDataDataContext()) 
{ 
    var vehicles = from a in db.EquipmentMainGenerals 
        join b in db.EquipmentMainConditions on a.wdEquipmentMainGeneralOID equals b.wdEquipmentMainGeneralOID 
        where b.Retired == null 
        orderby a.VehicleId 
        select a; 

    et = new EquipmentTable[vehicles.Count()]; 

    foreach (var vehicle in vehicles) 
    { 
     // Move data to the array 

     // Rates 
     GetVehcileRates(vehicle.wdEquipmentMainGeneralOID); 

     // Build the costs accumulators 
     GetPartsAndOilCosts(vehicle.VehicleId); 
     GetAccidentAndOutRepairCosts(vehicle.wdEquipmentMainGeneralOID); 

     // Last Month's Accumulators 
     et[i].lastMonthActualGasOil = GetFuel(vehicle.wdEquipmentMainGeneralOID) + Convert.ToDecimal(oilCost); 
     et[i].lastMonthActualParts = Convert.ToDecimal(partsCost); 
     et[i].lastMonthActualLabor = GetLabor(vehicle.VehicleId); 
     et[i].lastMonthActualOutRepairs = Convert.ToDecimal(outRepairCosts); 
     et[i].lastMonthActualAccidentCosts = Convert.ToDecimal(accidentCosts); 

     // Move more data to the array 

     i++; 
    } 
} 

ГЭТ методы все похожи на:

private void GetPartsAndOilCosts(string vehicleKey) 
{ 
    oilCost = 0; 
    partsCost = 0; 

    using (CarteGraphDataDataContext db = new CarteGraphDataDataContext()) 
    { 
     try 
     { 
     var costs = from a in db.WorkOrders 
        join b in db.MaterialLogs on a.WorkOrderId equals b.WorkOrder 
        join c in db.Materials on b.wdMaterialMainGeneralOID equals c.wdMaterialMainGeneralOID 
        where (monthBeginDate.Date <= a.WOClosedDate && a.WOClosedDate <= monthEndDate.Date) && a.EquipmentID == vehicleKey 
        group b by c.Fuel into d 
        select new 
          { 
           isFuel = d.Key, 
           totalCost = d.Sum(b => b.Cost) 
          }; 

      foreach (var cost in costs) 
      { 
      if (cost.isFuel == 1) 
      { 
       oilCost = (double)cost.totalCost * (1 + OVERHEAD_RATE); 
      } 
      else 
      { 
       partsCost = (double)cost.totalCost * (1 + OVERHEAD_RATE); 
      } 
      } 
     } 
     catch (InvalidOperationException e) 
     { 
      oilCost = 0; 
      partsCost = 0; 
     } 
    } 

    return; 
} 

Мое мышление здесь вырубку количество запросов к БД должно ускорить обработки. Если LINQ делает SELECT для каждой записи, возможно, мне нужно сначала загрузить каждую запись в память.

Я все еще считаю себя новичком с C# и ООП вообще (в основном я программирую RPG на iSeries). Поэтому я предполагаю, что делаю что-то глупое. Можете ли вы помочь мне исправить мою глупость (по крайней мере, с этой проблемой)?

Обновление: Мысль о том, что я вернусь и уточню, что я обнаружил. Похоже, что база данных была плохо разработана. Независимо от того, что LINQ генерировал в фоновом режиме, это был очень неэффективный код. Я не говорю, что LINQ плохо, это просто плохо для этой базы данных. Я преобразовал в быстро сложенную комбинацию. Настройка XSD и время обработки пошли от 1,25 минуты до 15 секунд. Как только я сделаю правильный редизайн, я могу только догадываться, что я побей еще несколько секунд. Спасибо всем вам за комментарии. Я попробую LINQ снова через день в лучшей базе данных.

+0

Мои собственные 2 цента, datatables не имеют никакого места в коде в этом десятилетии. –

ответ

7

Есть несколько вещей, которые я пятно в коде:

  1. Вы опрашивать несколько раз к базе данных для каждого элемента опрашивать «Var транспортных средств», вы можете переписать этот запрос, так что меньше базы данных требуются запросы.
  2. Если вам не нужны все свойства запрашиваемого объекта или нужны сущности этого объекта, лучше использовать анонимный тип в select. LINQ to SQL будет анализировать это и получать меньше данных из вашей базы данных. Такой выбор может выглядеть так: select new { a.VehicleId, a.Name }
  3. Запрос в GetPartsAndOilCosts может быть оптимизирован путём вычисления cost.totalCost * (1 + OVERHEAD_RATE) в запросе LINQ. Таким образом, запрос может быть полностью выполнен в базе данных, что должно сделать его намного быстрее.
  4. Вы делаете Count() по запросу var vehicles, но используете его только для определения размера массива. Хотя LINQ to SQL сделает очень эффективный запрос SELECT count(*), он требует дополнительной поездки туда и обратно в базу данных. Кроме того (в зависимости от уровня изоляции) время начала повторения запроса может быть добавлено. В этом случае ваш массив слишком мал и будет выброшен ArrayIndexOutOfBoundsException. Вы можете просто использовать .ToArray() по запросу или создать List<EquipmentTable> и позвонить по телефону .ToArray(). Обычно это будет достаточно быстро, особенно если у вас есть только 380 элементов в этой коллекции, и это, безусловно, будет быстрее, чем дополнительная обратная связь с базой данных (счет).
  5. Как вы, вероятно, уже ожидаете, количество запросов к базе данных является реальной проблемой. Переключение между массивом struct или DataTable не будет отличаться.
  6. После того как вы оптимизировали как можно больше запросов, начните анализ оставшихся запросов (используя профилировщик SQL) и оптимизируйте эти запросы с помощью мастера настройки индексов. Он предложит вам некоторые новые индексы, которые могут значительно ускорить процесс.

Немного дополнительного объяснения пункт № 1. То, что вы здесь делаете немного как это:

Что вы должны попытаться выполнить это, чтобы удалить query2 подзапрос, поскольку он выполняется на каждой строке верхнего запроса. Таким образом, вы могли бы в конечном итоге с чем-то вроде этого:

var query = 
    from x in A 
    from y in B 
    where x.Value == y.Value 
    select something; 

foreach (var row in query) 
{ 
} 

Конечно, этот пример является упрощенным и в реальной жизни он получает довольно сложным (как вы уже заметили). В вашем случае также потому, что у вас есть несколько таких подзапросов. Это может занять некоторое время, чтобы получить это право, особенно с вашим недостатком знаний LINQ to SQL (как вы сказали сами).

Если вы не можете понять это, вы всегда можете попросить снова здесь, в Stackoverflow, но, пожалуйста, не забывайте снимать проблему с наименьшей возможной вещью, потому что это не забавно читать чью-то беспорядок (мы не получаем заплатил за это) :-) Удачи.

+0

@Steven: Извините, я смущен # 1. Я не уверен, как это сделать. Все ваши другие моменты, на которые я смотрю. –

+0

@Mike: Я обновил свой ответ. – Steven

+0

Спасибо за обновление. Я посмотрю. –

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