我有一个基于 .net Web API 的项目,带有实体框架核心和 Azure Sql 数据库。
以下是我的数据模型,删除了额外的属性:
我在数据库上下文中有两个表,Parent 和 Children,具有父子关系。我为该类型提供了简单的名称来解释问题:
[Table("Parent")]
public record Parent
{
[Key]
public string ParentId { get; set; }
public virtual ICollection<Children1> Children1s { get; set; }
// other properties
}
[Table("Children1")]
public record Children1
{
[Key]
public string Children1Id { get; set; }
[ForeignKey("ParentId")]
public virtual Parent Parent { get; set; }
public virtual ICollection<Children2> Children2s { get; set; }
// many properties
}
我正在尝试获取所有父项目和链接的 Children1 项目,其中 Children1.另外,我还想为 Children1 获取 Children2。
我想为每个家长按日期(例如加入日期、上次/最近加入)订购的每个家长的其他孩子1中获取孩子1项目。
通过 Select 使用投影的方法中的存储库代码:
var query = context.Parents
.AsNoTracking()
.Select(p => new
{
p.ParentId,
p.Description,
Children1s = d.Children1s
.OrderByDescending(c => c.JoiningDate)
.Take(1)
.Select(c => new
{
c.ChildrenId,
c.Description
// other properties
}).ToList()
});
使用
Include
和 ThenInclude
的方法中的存储库代码:
var result = context.Parents
.AsNoTracking()
.Include(d => d.Children1s
.OrderByDescending(l => l.JoiningDate)
.Take(1))
.ThenInclude(l => l.Children2s)
.ToList();
另外,我还在全球范围内使用
UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
。
我的数据库有大约 20,000 条 Parent 记录,45,000 条 Children1 记录,大约 20,000 条 Children2 记录。
我还为用于 where、orderby 调用的每个表和字段都有索引。
Children1 大约有 200 列,这是一个旧表,我无法更改架构。
当我查看这两个选项生成的 SQL 时,即。通过投影和 Include,虽然我使用 select 只定位我需要的字段,但生成的 SQL 具有 Children1 中用于连接的所有字段 -
LEFT JOIN
。
由于此问题,Azure SQL 数据库中的查询非常慢。
如何控制EF只使用部分字段进行LEFT JOIN以加快查询速度?有/没有导航属性还有其他替代方法可以实现此目的吗?
似乎导航属性适合 1:1 关系,但由于 LEFT JOIN sql EF 生成,我需要对 1:n 关系执行的操作很慢。
我尝试了使用 Select 进行投影的各种方法,但我无法减少数量。用于连接的列。当我在线研究时,我了解了单一查询与拆分查询。所以,我现在使用后者,它稍微提高了性能。
您可以使用表拆分将数据库记录分区为两个或多个 EF Core 实体。 您可以通过共享主键来执行此操作 - 依赖实体的 PK 也是主体实体 PK 的 FK。 仅包含数据库中常用的字段作为主体实体中的属性,以最大限度地减少返回的字段。 当需要依赖实体中的字段时,您可以像添加任何其他导航属性一样简单地包含它们。
public class Principal
{
public int Id { get; set; }
public string PrincipalProperty { get; set; }
}
public class Dependent
{
public int Id { get; set; }
public string DependentProperty { get; set; }
}
// In OnModelCreating method
modelBuilder.Entity<Principal>( u =>
{
u.ToTable("TableNameHere");
...
});
modelBuilder.Entity<Dependent>( u =>
{
// use same table name
u.ToTable("TableNameHere")
.HasOne<Principal>()
.WithOne()
// dependent PK is the FK
.HasForeignKey<Dependent>( d => d.Id );
});