我必须在您的数据库上放置一个复杂的查询。但查询结束时间为8000毫秒。我做错了吗?我使用.net 1.1和Entity Framework核心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();
答案 0 :(得分:2)
查看您为服务器生成的SQL查询(以及此查询的结果)。对于SQL Server,最好的选择是SQL Server Profiler,也有其他服务器的方法。
您创建了两个查询。首先创建fol
数组,然后使用Contains将其传递给第二个查询。你知道这是怎么回事吗?您可能使用与数组中的许多项一样多的参数生成查询。它既不漂亮也不高效。这里没有必要,将它合并到主查询中,你只有一个参数。
你在过滤之前做分页,这真的应该是这样吗?还要看一下基于id过滤的其他分页方式,而不是简单的跳过。
您在一个查询中执行了太多的旁边查询。当您查询每个包含100个项目的三个子列表时,您不会获得300行。要在一个查询中获取它,您创建连接并实际获得100 * 100 * 100 = 1000000行。除非您确定框架可以将其拆分为多个查询(可能不能),否则您应该在单独的查询中查询子列表。这可能是您遇到的主要性能问题。
请使用单数来命名表格,而不是复数
对于性能分析,索引结构和执行计划是至关重要的信息,没有它们你就不能说太多了
答案 1 :(得分:1)
如评论中所述,您可能正在执行100,1000或10000次查询。对于数据库中与第一个结果匹配的每个Vote
,您执行3个其他查询。
对于第一个查询产生的1000票,您需要执行3000个其他查询来获取数据。那太疯了!
您必须使用EF Cores eager loading功能,只需很少的查询即可获取此数据。如果您的模型设计得很好,relations and navigation properties很容易。
当您在没有投影的情况下加载平面模型时(使用.Select
),您必须使用.Include
来告知EF应加载哪些其他相关实体。
// Assuming your navigation property is called VoteMedia
await _context.Votes.
.Include(vote => vote.VoteMedia)
...
这将通过投票加载所有VoteMedia
个对象。因此不需要额外的查询来获取它们。
但是如果您使用项目,则.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 => ... );
}