简体   繁体   English

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

[英]A table join in MVC application is being very slow

I'm at a bit of a loss as to why one of my ASP views in my MVC application is running so slow. 我对为什么MVC应用程序中的一个ASP视图运行这么慢感到有些困惑。

I select some data using linq in the controller. 我在控制器中使用linq选择一些数据。 This runs quickly: 这运行很快:

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


        }

I then do a foreach loop in the ASP view, going through each row of the data of type 'reviewitem' which has been passed to the view. 然后,我在ASP视图中执行一个foreach循环,遍历已传递给视图的“ reviewitem”类型的数据的每一行。 Again this is fast: 再次,这很快:

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

I need some more information to display, so I need to join to the 'Review' table (which again gives fast results) and then to the 'Student' table. 我需要显示更多信息,因此我需要加入“ Review”表(再次提供快速结果),然后加入“ Student”表。 This is where the problem is and it starts taking upwards of 30 seconds: 这是问题所在,它开始需要30秒钟以上的时间:

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

Each review item links through to one unique student so I don't understand why it is taking so long. 每个评论项目都链接到一个独特的学生,所以我不明白为什么要花这么长时间。 Does anyone have any ideas where I should start looking to see why it is so slow? 有没有人有什么想法我应该开始寻找为什么它这么慢? Presumably it is something to do with the 'Student' table (which is actually a SQL Server view) but I can select all rows from it in under a second using SQL? 大概与“学生”表(实际上是SQL Server视图)有关,但是我可以在一秒钟之内使用SQL从表中选择所有行吗?

When you write a LINQ query the query is not actually executed until you need the data (see delayed execution). 编写LINQ查询时,直到需要数据时才真正执行查询(请参阅延迟执行)。 Your first db call is not made until you foreach over ri.Progress, which is a single call. 直到您通过ri.Progress进行遍历,这才是您的第一个数据库调用,这是单个调用。

When you then ask for ri.Review.Student you are asking for additional data. 然后,您要求ri.Review.Student时,您正在要求其他数据。 So you make a call to the database. 因此,您可以调用数据库。 Because you are in a foreach loop you are making a single call to the database for each item in that loop. 因为您处于一个foreach循环中,所以您将对该循环中的每个项目进行一次数据库调用。

This is a "Linq n+1" problem. 这是一个“ Linq n + 1”问题。 To solve it, you should get all the data in one query. 要解决它,您应该在一个查询中获得所有数据。 You can either populate a model class and strongly type the view to that, or I think you can use the Linq .Include method to include the Student data in the selection 您可以填充模型类并为其强力键入视图,或者我认为您可以使用Linq .Include方法在选择中包括Student数据。

You can take a look at what calls are being made by firing up SQL server profiler and performing a trace 您可以通过启动SQL Server Profiler并执行跟踪来查看正在执行的调用

When you are requesting student data in the foreach loop, you are making loads of queries to the database: One for each time the loop is repeated (search for N+1 problem if interested). 当您在foreach循环中请求学生数据时,您正在对数据库进行大量查询:每次重复循环一次(如果感兴趣,请搜索N + 1问题)。

Changing the query with the include method and making it a list (to avoid the delayed execution) should solve your problem: 使用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();

After the above answers helpfully pointed out that this was an n+1 problem I did a bit of Googling. 在上述答案有帮助地指出这是一个n + 1问题之后,我做了一次谷歌搜索。 The include method did not work for me (my var type was IQueryable not ObjectQuery) but I did find a solution here: http://l2sprof.com/Learn/Alerts/SelectNPlusOne include方法对我不起作用(我的var类型是IQueryable而不是ObjectQuery),但在这里确实找到了解决方案: http : //l2sprof.com/Learn/Alerts/SelectNPlusOne

By adding this code just before my linq query, the page loads very quickly: 通过在linq查询之前添加此代码,页面可以非常快速地加载:

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

you can resolved this problem only by creating a store procedure in a sql server (which returns select statement with all columnsof your result) and then update your Entity framework with new complex type and associate this newly complex type with return type of your function import in selected store procedure 您只能通过在sql服务器中创建存储过程(返回带有结果所有列的select语句),然后使用新的复杂类型更新Entity框架并将此新的复杂类型与函数导入的返回类型相关联,来解决此问题。选择的存储过程

Result will many times faster than as beforee in linq Join 结果将比linq Join更快

this will more helpful..i think new procedure => update EF => new ComplexType(same name and type of select statemnet columns)=>Add function import(right click on procedure)=> link new complex type(in returns type) 这将更有用。.我认为新过程=>更新EF =>新ComplexType(选择statemnet列的名称和类型相同)=>添加函数import(右键单击过程)=>链接新复杂类型(返回类型)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM