简体   繁体   English

实体框架查询太慢

[英]Entity Framework Query is too slow

I have to put a complex query on your database. 我必须对您的数据库进行复杂的查询。 But the query ends at 8000 ms. 但是查询结束于8000毫秒。 Do I do something wrong? 我做错什么了吗? I use .net 1.1 and Entity Framework core 1.1.2 version. 我使用.net 1.1和Entity Framework core 1.1.2版本。

var fol = _context.UserRelations
                  .Where(u => u.FollowerId == id && u.State == true)
                  .Select(p => p.FollowingId)
                  .ToArray();

var Votes = await _context.Votes
                          .OrderByDescending(c => c.CreationDate)
                          .Skip(pageSize * pageIndex)
                          .Take(pageSize)
                          .Where(fo => fol.Contains(fo.UserId))
                          .Select(vote => new
                {
                    Id = vote.Id,
                    VoteQuestions = vote.VoteQuestions,
                    VoteImages = _context.VoteMedias.Where(m => m.VoteId == vote.Id)
                        .Select(k => k.MediaUrl.ToString()),

                    Options =  _context.VoteOptions.Where(m => m.VoteId == vote.Id).Select( ques => new
                    {
                        OptionsID = ques.Id,
                        OptionsName =  ques.VoteOption,
                        OptionsCount =  ques.VoteRating.Count(cout => cout.VoteOptionsId == ques.Id),
                    }),
                    User = _context.Users.Where(u => u.Id == vote.UserId).Select(usr => new
                    {
                        Id = usr.Id,
                        Name = usr.UserProperties.Where(o => o.UserId == vote.UserId).Select(l => l.Name.ToString())
                            .First(),
                        Surname = usr.UserProperties.Where(o => o.UserId == vote.UserId)
                            .Select(l => l.SurName.ToString()).First(),
                        ProfileImage = usr.UserProfileImages.Where(h => h.UserId == vote.UserId && h.State == true)
                            .Select(n => n.ImageUrl.ToString()).First()
                    }),
                    NextPage = nextPage
                }).ToListAsync();

Have a look at the SQL queries you generate to the server (and results of this queries). 查看您生成的对服务器的SQL查询(以及此查询的结果)。 For SQL Server the best option is SQL Server Profiler, there are ways for other servers too. 对于SQL Server,最好的选择是SQL Server Profiler,也可以使用其他服务器。

  • you create two queries. 您创建两个查询。 First creates fol array and then you pass it into the second query using Contains. 首先创建fol数组,然后使用Contains将其传递给第二个查询。 Do you know how this works? 你知道这是怎么回事吗? You probably generate query with as many parameters as many items you have in the array. 您生成的查询可能与数组中包含的所有项目一样多。 It is neither pretty or efficient. 它既不美观也不高效。 It is not necessary here, merge it into the main query and you would have only one parameter. 这里没有必要,将其合并到主查询中,您将只有一个参数。

  • you do paginating before filtering, is this really the way it should work? 您在过滤之前先进行分页,这真的是应该工作的方式吗? Also have a look at other ways of paginating based on filtering by ids rather than simple skipping. 还要看看其他基于id过滤而不是简单跳过的分页方法。

  • you do too much side queries in one query. 您在一个查询中执行过多的副查询。 When you query three sublists of 100 items each, you do not get 300 rows. 当查询三个每个100项的子列表时,不会得到300行。 To get it in one query you create join and get actually 100*100*100 = 1000000 rows. 要在一个查询中获取它,您可以创建联接并实际上获得100 * 100 * 100 = 1000000行。 Unless you are sure the frameworks can split it into multiple queries (probably can not), you should query the sublists in separate queries. 除非您确定框架可以将其拆分为多个查询(可能无法),否则应在单独的查询中查询子列表。 This would be probably the main performance problem you have. 这可能是您遇到的主要性能问题。

  • please use singular to name tables, not plural 请使用单数命名表格,而不是复数

  • for performance analysis, indexes structure and execution plan are vital information and you can not really say much without them 对于性能分析,索引结构和执行计划是至关重要的信息,没有它们,您真的不能说太多

As noted in the comments, you are potentially executing 100, 1000 or 10000 queries. 如注释中所述,您可能正在执行100、1000或10000个查询。 For every Vote in your database that matches the first result you do 3 other queries. 对于数据库中与第一个结果匹配的每个Vote ,您都要进行3个其他查询。

For 1000 votes which result from the first query you need to do 3000 other queries to fetch the data. 对于第一个查询产生的1000票,您需要执行3000个其他查询以获取数据。 That's insane! 太疯狂了!

You have to use EF Cores eager loading feature to fetch this data with very few queries. 您必须使用EF Cores 急切加载功能来通过很少的查询来获取此数据。 If your models are designed well with relations and navigation properties its easy. 如果您的模型设计得很好,并且具有关系和导航属性,那么这很容易。

When you load flat models without a projection (using .Select ), you have to use .Include to tell EF Which other related entities it should load. 当加载没有投影的平面模型时(使用.Select ),必须使用.Include来告诉EF应该加载哪些其他相关实体。

// Assuming your navigation property is called VoteMedia
await _context.Votes.
    .Include(vote => vote.VoteMedia)
    ...

This would load all VoteMedia objects with the vote. 这将使用投票加载所有VoteMedia对象。 So extra query to get them is not necessary. 因此,不需要额外的查询来获取它们。

But if you use projects, the .Include calls are not necessary (in fact they are even ignored, when you reference navigation properties in the projection). 但是,如果使用项目,则.Include调用(实际上,当您在投影中引用导航属性时,它们甚至会被忽略)。

// Assuming your navigation property is called VoteMedia
await _context.Votes.
    .Include(vote => vote.VoteMedia)
    ...
    .Select( vote => new
    {
        Id = vote.Id,
        VoteQuestions = vote.VoteQuestions,

        // here you reference to VoteMedia from your Model
        // EF Core recognize that and will load VoteMedia too.
        //
        // When using _context.VoteMedias.Where(...), EF won't do that
        // because you directly call into the context
        VoteImages = vote.VoteMedias.Where(m => m.VoteId == vote.Id)
            .Select(k => k.MediaUrl.ToString()),

        // Same here
        Options = vote.VoteOptions.Where(m => m.VoteId == vote.Id).Select( ques => ... );
    }

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

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