2015-02-18 6 views
0

Я использую MVC4 с Entity Framework 5 для проекта. У нас есть мастер-таблица с именем MAIN_TABLE и имеют несколько дочерних таблиц (то есть: CHILD_TABLE1, CHILD_TABLE2, и т.д ..)LINQ и EF Slow

Мы столкнулись с проблемой скорости выполнения запросов LINQ из нескольких опции фильтра в этих различных таблицах ребенка.

Мне нужно написать запрос для фильтрации данных из Модели с использованием EF5. Прямо сейчас мы закодированы на основе одного фильтра за раз. Т.е. мы проверяем каждый отфильтрованный столбцы и запускаем запрос. Но это слишком медленно. Есть ли другой вариант?

string[] strValue = filter_Values; 
foreach (SelectedData selectedData in objSelectedDataCollection.DataCollection) 
{ 
    switch (selectedData.ColumnName) // This is the column name in the GridView defined 
    { 
     case "Outlook": 
      indlist = from jd in indlist 
         where jd.IND_APP_PASS_STATUS.Any(
                ob => strValue.Contains(ob.Outlook)) 
         orderby jd.Indman_ID 
         select jd; 
      break; 
     case "RS_TP": 
      indlist = from jd in indlist 
         where jd.IND_APP_PASS_STATUS.Any(
                ob => strValue.Contains(ob.RS_TP)) 
         orderby jd.Indman_ID 
         select jd; 
      break; 
     case "Code": 
      indlist = (from jd in indlist from jk in jd.IND_APP_PASS_STATUS where strValue.Contains(jk.Code) select jd).ToList(); 
      break; 
    } 
} 
+0

Хмм не 'string.Contains()' фактически выполняется на вашем конце, а не на стороне SQL-сервера? Кто угодно? Если это так, то почему это медленно – MickyD

+8

Используйте профайлер SQL, чтобы узнать, какой запрос отправляется в механизм базы данных. Возможно, вам придется писать SQL вручную вместо использования EF, если вам нужно оптимизировать запрос. – JNYRanger

+0

@MickyDuncan, Linq To Entities преобразует 'strValue.Contains' в соответствующий SQL' IN (...) 'оператор. – haim770

ответ

0

Проблема была в запросе, который я написал.

Пожалуйста, проверьте нижеприведенный запрос. Теперь я использую «join» вместо запроса в подтемах.

ПРИМЕЧАНИЕ. Ответ заключается в том, что, если мы пишем запрос с использованием Subtables, каждая родительская строка попадает в каждую строку подтаблицы в базе данных. и по этой причине производительность вашего кода будет уменьшаться в соответствии с количеством rows.i.e. если подтаблица имеет 10 строк, она попадет в базу данных 10 раз. Но если мы используем «join» между двумя таблицами, теперь код будет ударяться только один раз с каждым столбцом.

var indlist = db.IND_TABLE 
      .Where(x => x.Package_No.Trim() != ""); 

string[] strValue = filter_Values; 
foreach (SelectedData selectedData in objSelectedDataCollection.DataCollection) 
{ 
    switch (selectedData.ColumnName) 
    { 
     case "Outlook": 
      indlist = (from jd in indlist join ipas in dbContext.IND_APP_PASS_STATUS on jd.Indman_ID equals ipas.Indman_ID where (strValue.Contains(ipas.Outlook)) orderby jd.Indman_ID select jd).ToList<IND_TABLE>(); 
      break; 

     case "RS_TP": 
      indmanlist = (from jd in indmanlist join ipas in dbContext.IND_APP_PASS_STATUS on jd.Indman_ID equals ipas.Indman_ID where (strValue.Contains(ipas.RS_TP)) orderby jd.Indman_ID select jd).ToList<IND_TABLE>(); 
      break; 

     case "Code": 
      indmanlist = (from jd in indmanlist join ipas in dbContext.IND_APP_PASS_STATUS on jd.Indman_ID equals ipas.Indman_ID where (strValue.Contains(ipas.Code)) orderby jd.Indman_ID select jd).ToList<IND_TABLE>(); 
      break; 
    } 
} 

Я использовал SQL Profiler для проверки расстрелов с базой данных. Затем я понимаю реальную проблему попадания в базу данных.

1

Есть две стороны эффективности EF - сервер и клиент (ваше приложение).

Во-первых, как упоминалось в комментариях, используется SQL-профайлер, чтобы узнать, как выполняется быстрый сгенерированный запрос.

Также обратите внимание на количество возвращенных записей. Временно switching automatic changes detection off для запросов, возвращающих особенно большой результирующий набор can give существенное повышение производительности.

1

Ваш комментарий первоначальный запрос базы данных

indlist = db.IND_TABLE 
      .ToList() 
      .Where(x => x.Package_No.Trim() != "") 
      .OrderBy(x => Int32.Parse(x.Package_No)) 
      .Select(x => x) 
      .ToList<IND_TABLE>(); 

Первый .ToList() означает, что вся IND_TABLE будут возвращены из базы данных. Затем вся другая фильтрация выполняется в коде. Это одна из причин низкой производительности - почти всегда лучше фильтровать на БД, чем возвращать все.

Также обратите внимание, что вы сортируете результаты несколько раз. Во-первых, при настройке indlist, а затем один раз на каждой итерации objSelectedDataCollection.DataCollection. Это не нужно, и вы не должны сортировать, пока не закончите фильтрацию. Возможно, после вашего цикла foreach у вас может быть линия indlist = indlist.OrderBy(x => x.Indman_ID);

Взяв все это вместе, вы получите следующее.

var indlist = db.IND_TABLE 
       .Where(x => x.Package_No.Trim() != ""); 

string[] strValue = filter_Values; 
foreach (SelectedData selectedData in objSelectedDataCollection.DataCollection) 
{ 
    switch (selectedData.ColumnName) 
    { 
     case "Outlook": 
      indlist = indlist.Where(il => il.IND_APP_PASS_STATUS.Any(iaps => strValue.Contains(iaps.Outlook))); 
      break; 
     case "RS_TP": 
      indlist = indlist.Where(il => il.IND_APP_PASS_STATUS.Any(iaps => strValue.Contains(iaps.RS_TP))); 
      break; 
     case "Code": 
      indlist = indlist.Where(il => il.IND_APP_PASS_STATUS.Any(iaps => strValue.Contains(iaps.Code))); 
      break; 
    } 
} 

indlist = indlist.OrderBy(x => x.Indman_ID).ToList(); 

Это стоит прочитать до того, когда Entity Framework создает SQL для запроса к базе данных (поиск термина «отложенное исполнение»). Это происходит только при попытке использовать результаты - например, с ToList(), ToArray(), SingleOrDefault() и другими вещами. Строка context.TableName.Where(some lambda expression); не будет вызывать запрос БД в этой точке. Вы можете продолжать фильтрацию с помощью Where без вызова БД, что и происходит в коде, который я опубликовал. SQL будет генерироваться только, а БД запрашивается в строке indlist = indlist.OrderBy(il => il.Indman_ID).ToList();

+0

В вышеприведенном ответе есть проблема, указанная выше функция возвращает нулевой элемент, если я не даю ToList() в конце секции фильтра (внутри Select case). – JKANNAN

+0

В дополнение к тому, чтобы быть осторожным, когда вы выполняете материальные запросы (которые, как я согласен, оказывают огромное влияние на производительность при использовании EF), мы также заметили, что оператор Any() иногда может генерировать очень субоптимальные запросы (в частности, когда запрашиваемый запрос применяется к сложным). Мы обнаружили, что оператор Count() кажется более «стабильным» с точки зрения генерации запросов и преобразовал все вхождения Any() в наш код в Count(). например myQueryable.Any (x => p (x)) становится myQueryable.Count (x => p (x))> 0. –

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