2012-03-30 2 views
1

Я немного теряю, почему одно из моих представлений ASP в моем приложении MVC работает так медленно.Соединение таблицы в приложении MVC очень медленное

Я выбираю некоторые данные, используя linq в контроллере. Это работает быстро:

public ActionResult Progress(int ID) 
     { 


      var reviewitems = from ri in db.ReviewItems 
         where ri.Enrolment.Course.LearningArea.LearningAreaID == ID && ri.Review.ReviewSeries.StartDate < DateTime.Now && ri.Review.ReviewSeries.EndDate > DateTime.Now && ri.Progress < 2 
         select ri; 


      return View("Progress", reviewitems); 


     } 

Я тогда сделать цикл по каждому элементу в представлении ASP, проходя через каждую строку данных типа «reviewitem», который был принят в представлении. Опять же, это быстро:

<%foreach (var ri in Model) 
    { %> 
<tr> 
<td><%= ri.Progress %></td> 
</tr> 
<%} %> 

мне нужно больше информации для отображения, так что мне нужно, чтобы присоединиться к столу «Review» (что опять-таки дает быстрые результаты), а затем к столу «Student». Это где проблема и она начинает принимать свыше 30 секунд:

<%foreach (var ri in Model) 
    { %> 
<tr> 
<td><%= ri.Review.Student.Surname %></td> 
</tr> 
<%} %> 

Каждый обзор ссылок запись до одного уникального студента, так что я не понимаю, почему он так долго. У кого-нибудь есть идеи, где я должен начать искать, почему это так медленно? Предположительно, это как-то связано с таблицей «Студент» (которая на самом деле является представлением SQL Server), но я могу выбрать из нее все строки за секунду, используя SQL?

+0

Как вы создаете связь между Review and Student, если Student является View? Используете ли вы Linq для Sql или Entity Framework? –

+0

@MystereMan Я не уверен быть честным - это приложение, которое я унаследовал от кого-то еще! У меня есть модель DBML в приложении MVC, которую я использую для настройки всех отношений, но я не знаю, является ли это модель данных Entity Framework или нет. – Chris

+0

DBML означает Linq to Sql. Честно говоря, если вы даже не знаете, какую технологию вы используете, я бы сказал, что вы над головой, и вам нужно немного узнать о том, с чем вы работаете. –

ответ

0

После вышеупомянутых ответов полезно было указано, что это была проблема n + 1. Я немного поработал с Google.Способ включает не работает для меня (мой тип вар был IQueryable не ObjectQuery), но я нашел решение здесь: http://l2sprof.com/Learn/Alerts/SelectNPlusOne

Добавив этот код непосредственно перед моей Linq запроса, страница загружается очень быстро:

var loadoptions = new DataLoadOptions(); 
     loadoptions.LoadWith<ReviewItem>(ri => ri.Review); 
     loadoptions.LoadWith<Review>(r => r.Student); 
     db.LoadOptions = loadoptions; 
6

Когда вы пишете запрос LINQ, запрос фактически не выполняется до тех пор, пока вам не понадобятся данные (см. Отложенное выполнение). Ваш первый вызов db не выполняется до тех пор, пока вы не запустите ri.Progress, который является одним вызовом.

Когда вы запрашиваете ri.Review.Student, вы запрашиваете дополнительные данные. Поэтому вы делаете звонок в базу данных. Поскольку вы находитесь в цикле foreach, вы делаете один вызов в базу данных для каждого элемента в этом цикле.

Это проблема с Linq n + 1. Чтобы решить эту проблему, вы должны получить все данные в одном запросе. Вы можете либо заполнить класс модели, либо сильно набрать это представление, или я думаю, что вы можете использовать метод Linq .Include для включения данных Student в выборку

Вы можете посмотреть, какие вызовы вызывают запускать профилировщик SQL-сервера и выполнять трассировку

+0

Хороший ответ. http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-anity-framework-data-model-for-an-asp-net-mvc-application объясняет все это. – RickAndMSFT

+0

@ Rick.Anderson-at-Microsoft.com - получается, он использует Linq-to-sql, а не ef. –

2

Когда вы запрашиваете данные о студентах в цикле foreach, вы делаете множество запросов в базу данных: по одному для каждого повторения цикла (поиск проблемы с N + 1, если интересно).

Изменение запроса с помощью метода включает в себя и сделать его список (чтобы избежать отложенного исполнения) должны решить вашу проблему:

 var reviewitems = (
      from ri in db.ReviewItems 
      where ri.Enrolment.Course.LearningArea.LearningAreaID == ID 
       && ri.Review.ReviewSeries.StartDate < DateTime.Now 
       && ri.Review.ReviewSeries.EndDate > DateTime.Now 
       && ri.Progress < 2 
      select ri 
      ).Include("Review.Student").ToList(); 
+0

У меня, похоже, нет метода «Включить». Похоже, это потому, что переменная reviewitems имеет тип IQueryable, тогда как метод Include для ObjectQuery. – Chris

+0

есть способ расширения для IQueryable, если я знаю. Попробуйте добавить 'using System.Data.Entity;' в файл. http://msdn.microsoft.com/en-us/library/gg696450(v=vs.103).aspx – Schiavini

-1

вы можете устраняющие эту проблему только путь создания процедуры сохранения на сервере SQL (который возвращает оператор select со всем столбцом вашего результата), а затем обновляет структуру Entity новым сложным типом и связывает этот новый сложный тип с возвращаемым типом импорта вашей функции в выбранной процедуре хранения.

Результат будет во много раз быстрее, чем в Предыдущее Следующее в linq Присоединиться

это будет более полезно..и думаю, new procedure => update EF => new ComplexType (то же имя и тип столбцов statemnet) => Добавить функцию import (щелкните правой кнопкой мыши по процедуре) => связать новый сложный тип (в типе возврата)

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