재우니의 블로그

 

 

 

EF 하위 쿼리에서 Contains LINQ 연산자를 사용하는 경우, 이제 EF Core는 EXISTS 대신 SQL IN을 사용하여 더 나은 쿼리를 생성합니다. 따라서 쿼리 속도가 크게 향상될 수 있습니다.

 

public class MyDbContext : DbContext
{
    public DbSet<Employee> Employees { get; set; }
 
    public DbSet<Department> Departments { get; set; }
}
 
public record Employee(string Name, int DepartmentId)
{
    public int Id { get; init; }
}
 
public record Department(string Name)
{
    public int Id { get; init; }
 
    public bool IsWfhAllowed { get; set; }
}

 

 

이제 재택 근무가 허용되는 모든 직원을 확보하고 싶다고 가정해 보겠습니다. 요구 사항에 대해 다음과 같은 LINQ 쿼리를 작성할 수 있습니다.

 

List<Employee> wfhEmployees = await context.Employees
    .Where(e => context.Departments
        .Where(d => d.IsWfhAllowed)
        .Select(d => d.Id)
        .Contains(e.DepartmentId))
    .ToListAsync();

 

 

 

EF 8.0 이전 버전(예: EF 7.x)을 사용 중인 경우 EF는 다음과 같은 쿼리를 생성합니다.

 

SELECT [e].[Id], [e].[DepartmentId], [e].[Name]
FROM [Employees] AS [e]
WHERE EXISTS (
    SELECT 1
    FROM [Departments] AS [d]
    WHERE [d].[IsWfhAllowed] = CAST(1 AS bit) AND [d].[Id] = [e].[DepartmentId])

 

 

여기서 하위 쿼리는 외부 [Employees] 테이블을 참조하고 있으므로 [Employees] 테이블의 각 행에 대해 하위 쿼리를 실행해야 합니다(상관관계된 하위 쿼리).

 

 

EF 8.0을 사용하면 EF는 다음 쿼리를 생성합니다.

 

SELECT [e].[Id], [e].[DepartmentId], [e].[Name]
FROM [Employees] AS [e]
WHERE [e].[DepartmentId] IN (
    SELECT [d].[Id]
    FROM [Departments] AS [d]
    WHERE [d].[IsWfhAllowed] = CAST(1 AS bit))

 

 

여기서 하위 쿼리는 더 이상 외부 테이블을 참조하지 않으므로 한 번만 평가할 수 있으므로 대부분의 데이터베이스 시스템에서 성능이 크게 향상됩니다.

 

참고: Microsoft SQL Server에서 데이터베이스는 성능이 동일할 수 있도록 첫 번째 쿼리를 두 번째 쿼리로 최적화할 수 있습니다.