我对EF Core和LINQ查询有问题.

我有这样的疑问:

_db.TrainingsExercises
   .Include(t => t.ExerciseSteps)
   .Where(te => te.UserId == userId);

这是在这两个型号上使用dbContext:

public class TrainingExercise
{
    [Key]
    public Guid Id { get; set; }
    public Guid UserId { get; set; }
    public string Name { get; set; }
    public bool IsPublic { get; set; }
    [ForeignKey(nameof(UserId))]
    public User User { get; set; }
    public ICollection<TrainingExerciseStep> ExerciseSteps { get; set; }
    public ICollection<TeamTrainingExercise>? TeamTrainings { get; set; }
}

public class TrainingExerciseStep
{
    [Key]
    public Guid Id { get; set; }
    public Guid TrainingExerciseId { get; set; }
    public int Order { get; set; }
    public string? Name { get; set; }
    public string? Image { get; set; }
    [ForeignKey(nameof(TrainingExerciseId))]
    public TrainingExercise TrainingExercise { get; set; }
    public List<TrainingExerciseStepComponents> ExerciseStepComponents { get; set; }
}

appContext是这样设置的:

public DbSet<TrainingExercise> TrainingsExercises { get; set; }
public DbSet<TrainingExerciseStep> TrainingExerciseSteps { get; set; }

builder.Entity<TrainingExercise>(entity =>
{
    entity.HasMany(u => u.ExerciseSteps)
          .WithOne(s => s.TrainingExercise);
});

这是创建一个带有左连接的简单查询,我在SQL Server上执行该查询,不需要几秒钟,但Linq查询需要一分钟以上的时间.

先谢谢你.

我试着go 掉了Include,然后它就完美地工作了.也加了AsNoTracking,还是一样的.

推荐答案

此查询:

_db.TrainingsExercises
   .Include(t => t.ExerciseSteps)
   .Where(te => te.UserId == userId);

...实际上不会执行任何事情,所以这一行本身不会导致您1分钟的延迟.查询在您使用IQueryable时执行,例如使用ToListFirst等或使用foreach迭代.因此,查看如何使用该查询可能有助于了解可能影响性能的问题.

在研究可在开发环境中重现的性能问题时,一个简单的步骤是使用调试器单步执行,并注意到执行速度较慢的任何特定行.这可能是一行花了很长时间,或者循环中的某个东西花了一两秒钟,但却导致某个东西执行了很多次.这可以与针对数据库的分析器配合使用,以查看正在运行哪些SQL语句.

.AsSplitQuery()可以帮助消除笛卡尔乘积,尽管在单个一对多关系中,字段的数量相对有限,这通常不是一个很大的因素.其中一个罪魁祸首可能是如果练习步骤中的一些数据恰好相当大.如果包含位图的Base64表示形式,则"Image"是可疑的.如果练习步骤具有较大的图像组件,您通常不希望/需要一直返回该组件,尤其是在检索可能包含多组步骤的大量练习时.在这里,您的 Select 是使用Projection,而不是加载和返回实体,而是创建简单的C#类作为视图模型或DTO,这些类只包含使用.Select()的查询结果所需的列,并排除昂贵的字段(S).更好的方法是标准化数据库中的昂贵字段:例如,具有TrainingExerciseStepId和This Image列的1对1表TrainingExerciseStepImage.这样,您可以加载训练练习及其步骤,而无需返回昂贵的专栏(S),并且只有在实际需要这些图像时才能加载这些图像.(即针对单个步骤,而不是针对用户的每个练习的每个步骤.)

如果有在加载步骤列表时显示图像的用例,您可以考虑添加对附加缩略图的支持,如果用户能够上传任何大小的图像,缩略图将是完整图像的缩小副本.例如,您可能正在显示一个步骤列表,其中的图像只有100x100像素,但加载的图像内容可以以600dpi全屏显示.

Asp.net相关问答推荐

502 DotNet WebApplication的网关nginx已损坏

如何在 ASP.NET RadioButtonList 中的项目之间添加空格

log4net 记录所有未处理的应用程序错误

将 Global.asax 迁移到 Startup.cs

是否可以使用 Membership API 更改用户名

如何使用 SmtpClient.SendAsync 发送带有附件的邮箱?

如何将配置转换应用于外部配置文件

如果站点在 localhost 或 127.0.0.1 上运行,如何判断 ASP.NET MVC 视图

ASP.NET MVC4 jquery/javascript 包的使用

相当于服务器端的 ASP.NET 包括

IIS 7.5 上没有 asp.net 功能

Devexpress 或 Telerik Controls 比较

IIS 6.0 通配符映射基准?

来自 IP 地址的经度和纬度值

反序列化客户端 AJAX JSON 日期

如何确定服务器端 C# 上的浏览​​器窗口大小

设置 Response.Status 生成HTTP 状态字符串无效异常

对于 DB ID,需要一个较小的 GUID 替代方案,但对于 URL 仍然是唯一且随机的

IIS 8.0 ASP.NET 和错误 500.19

连接字符串正确时出现实例失败错误