MVC应用程序中的表联接非常缓慢

本文关键字:非常 缓慢 应用程序 MVC | 更新日期: 2023-09-27 18:29:36

我有点不明白为什么我的MVC应用程序中的一个ASP视图运行如此缓慢。

我在控制器中使用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视图中执行foreach循环,遍历已传递给视图的"reviewitem"类型数据的每一行。同样,这很快:

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

我需要更多的信息来显示,所以我需要加入"复习"表(再次给出快速结果),然后加入"学生"表。这就是问题所在,它开始需要30秒以上的时间:

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

每个复习项目都链接到一个独特的学生,所以我不明白为什么要花这么长时间。有人知道我应该从哪里开始寻找为什么它如此缓慢吗?据推测,这与"Student"表(实际上是SQL Server视图)有关,但我可以在一秒钟内使用SQL从中选择所有行?

MVC应用程序中的表联接非常缓慢

编写LINQ查询时,在需要数据之前,查询不会实际执行(请参阅延迟执行)。你的第一个db调用直到你在ri上foreach才发出。进步,这是一个单一的呼吁。

当你问ri的时候。复习。学生,你在要求更多的数据。所以你调用了数据库。因为您处于foreach循环中,所以您将对该循环中的每个项目的数据库进行一次调用。

这是一个"林n+1"问题。要解决此问题,您应该在一个查询中获取所有数据。你可以填充一个模型类并强烈键入视图,或者我认为你可以使用Linq.Include方法将Student数据包括在选择中

您可以通过启动SQL服务器探查器并执行跟踪来查看正在进行的调用

当您在foreach循环中请求学生数据时,您将对数据库进行大量查询:每次循环重复一次查询(如果感兴趣,请搜索N+1问题)。

使用include方法更改查询并将其列为列表(以避免延迟执行)应该可以解决您的问题:

        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();

在上面的答案有力地指出这是一个n+1问题后,我在谷歌上搜索了一下。include方法对我不起作用(我的var类型是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;

只有在sql server中创建一个存储过程(返回select语句和结果的所有列),然后用新的复杂类型更新您的实体框架,并将此新复杂类型与所选存储过程中函数导入的返回类型关联

结果将比以前快很多倍加入

这会更有帮助。。我想new procedure=>update EF=>new ComplexType(与select statemnet列的名称和类型相同)=>Add function import(右键单击procedure)=>link new complex type(在返回类型中)