NativeAOT 지원 및 미리 컴파일된 쿼리(실험적)
Warning
NativeAOT 및 쿼리 사전 컴파일은 매우 실험적인 기능이며 프로덕션 사용에는 아직 적합하지 않습니다. 아래에 설명된 지원은 최종 기능에 대한 인프라로 간주되어야 하며, 이는 EF 10과 함께 릴리스될 가능성이 높습니다. 현재 지원을 실험하고 환경에 대해 보고하는 것이 좋지만 프로덕션 환경에서 EF NativeAOT 애플리케이션을 배포하지 않는 것이 좋습니다. 알려진 특정 제한 사항은 아래를 참조하세요.
.NET 네이티브AOT를 사용하면 AOT(미리 컴파일된) 자체 포함 .NET 애플리케이션을 게시할 수 있습니다. 이렇게 하면 다음과 같은 이점이 제공됩니다.
- 애플리케이션 시작 시간이 훨씬 빨라집니다.
- 메모리 공간이 더 작고 배포하기 쉬운 작은 자체 포함 이진 파일
- Just-In-Time 컴파일이 지원되지 않는 환경에서 애플리케이션 실행
NativeAOT를 사용하여 게시된 EF 애플리케이션은 해당 애플리케이션이 없는 동일한 애플리케이션보다 훨씬 빠르게 시작됩니다. NativeAOT에서 제공하는 일반적인 .NET 시작 개선 사항(즉, 매번 JIT 컴파일이 필요하지 않음) 외에도 EF는 애플리케이션을 게시할 때 LINQ 쿼리를 미리 컴파일하므로 시작할 때 처리가 필요하지 않으며 SQL을 즉시 실행할 수 있습니다. 애플리케이션의 코드에 있는 EF LINQ 쿼리가 많을수록 시작이 더 빨라질 것으로 예상됩니다.
EF NativeAOT 애플리케이션 게시
먼저 다음과 같이 프로젝트에 대해 NativeAOT 게시를 사용하도록 설정합니다.
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
NativeAOT에서 LINQ 쿼리 실행에 대한 EF의 지원은 쿼리 사전 컴파일에 의존합니다. 이 메커니즘은 정적으로 EF LINQ 쿼리를 식별하고 각 특정 쿼리를 실행하는 코드를 포함하는 C# 인터셉터를 생성합니다. 이렇게 하면 애플리케이션이 시작될 때마다 LINQ 쿼리를 SQL로 처리하고 컴파일하는 작업을 많이 수행하지 않아 애플리케이션의 시작 시간이 크게 단축됩니다. 대신 각 쿼리의 인터셉터에는 데이터베이스 결과를 .NET 개체로 구체화하는 최적화된 코드뿐만 아니라 해당 쿼리에 대한 최종 SQL이 포함됩니다.
C# 인터셉터는 현재 실험적 기능이며 프로젝트 파일에 특별한 옵트인이 필요합니다.
<PropertyGroup>
<InterceptorsNamespaces>$(InterceptorsPreviewNamespaces);Microsoft.EntityFrameworkCore.GeneratedInterceptors</InterceptorsNamespaces>
</PropertyGroup>
마지막으로, 패키지에는 애플리케이션을 Microsoft.EntityFrameworkCore.Tasks
게시할 때 쿼리 사전 컴파일을 수행하고 필요한 컴파일된 모델을 생성하는 MSBuild 통합 이 포함되어 있습니다.
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tasks" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
이제 EF NativeAOT 애플리케이션을 게시할 준비가 되었습니다.
dotnet publish -r linux-arm64 -c Release
ARM64에서 실행되는 Linux용 NativeAOT 게시를 보여줍니다. 이 카탈로그 를 참조하여 런타임 식별자를 찾습니다. 게시하지 않고 인터셉터를 생성하려는 경우(예: 생성된 원본을 검사하는 경우) 명령을 통해 dotnet ef dbcontext optimize --precompile-queries --nativeaot
수행할 수 있습니다.
C# 인터셉터가 작동하는 방식으로 인해 애플리케이션 원본의 변경 내용이 무효화되고 위의 프로세스를 반복해야 합니다. 따라서 인터셉터 생성 및 실제 게시는 개발자가 코드 작업을 수행하므로 내부 루프에서 발생하지 않을 것으로 예상됩니다. 대신 CI/CD 시스템의 게시/배포 워크플로에서 둘 다 dotnet ef dbcontext optimize
dotnet publish
실행할 수 있습니다.
참고 항목
게시는 현재 여러 트리밍 및 NativeAOT 경고를 보고하므로 애플리케이션이 제대로 실행되지는 않습니다. 이는 NativeAOT 지원의 현재 실험 상태를 고려할 때 필요합니다. 실험적이지 않은 최종 기능은 경고를 보고하지 않습니다.
제한 사항
동적 쿼리는 지원되지 않습니다.
쿼리 사전 컴파일은 소스 코드의 정적 분석을 수행하여 EF LINQ 쿼리를 식별하고 C# 인터셉터를 생성합니다. LINQ를 사용하면 LINQ 연산자가 임의의 조건에 따라 구성되는 매우 동적 쿼리를 표현할 수 있습니다. 이러한 쿼리는 정적으로 분석할 수 없으며 현재 지원되지 않습니다. 다음 예시를 참조하세요.
IAsyncEnumerable<Blog> GetBlogs(BlogContext context, bool applyFilter)
{
IQueryable<Blog> query = context.Blogs.OrderBy(b => b.Id);
if (applyFilter)
{
query = query.Where(b => b.Name != "foo");
}
return query.AsAsyncEnumerable();
}
위의 쿼리는 여러 문으로 분할되고 외부 매개 변수를 기반으로 연산자를 동적으로 작성 Where
합니다. 이러한 쿼리는 미리 컴파일할 수 없습니다. 그러나 이러한 동적 쿼리를 여러 비동기 쿼리로 다시 작성할 수 있는 경우도 있습니다.
IAsyncEnumerable<Blog> GetBlogs(BlogContext context, bool applyFilter)
=> applyFilter
? context.Blogs.OrderBy(b => b.Id).Where(b => b.Name != "foo").AsAsyncEnumerable()
: context.Blogs.OrderBy(b => b.Id).AsAsyncEnumerable();
두 쿼리는 각각 처음부터 끝까지 정적으로 분석할 수 있으므로 미리 컴파일에서 처리할 수 있습니다.
동적 쿼리는 나중에 NativeAOT를 사용할 때 지원될 수 있습니다. 그러나 미리 컴파일할 수 없으므로 애플리케이션 시작 속도가 계속 느려지고 일반적으로 NativeAOT가 아닌 실행에 비해 덜 효율적으로 수행됩니다. 이는 EF가 내부적으로 코드 생성을 사용하여 데이터베이스 결과를 구체화하지만 NativeAOT를 사용하는 경우 코드 생성이 지원되지 않기 때문입니다.
기타 제한 사항
- LINQ 쿼리 식 구문("이해 구문"이라도 함)은 지원되지 않습니다.
- 생성된 컴파일된 모델 및 쿼리 인터셉터는 현재 코드 크기 측면에서 상당히 클 수 있으며 생성하는 데 시간이 오래 걸릴 수 있습니다. 이를 개선할 계획입니다.
- EF 공급자는 미리 컴파일된 쿼리를 지원하기 위해 빌드해야 할 수 있습니다. 공급자의 설명서를 확인하여 EF의 NativeAOT 지원과 호환되는지 확인합니다.
- 캡처된 상태를 사용하는 값 변환기는 지원되지 않습니다.
NativeAOT가 없는 미리 컴파일된 쿼리
EF의 NativeAOT 지원의 현재 제한 사항으로 인해 일부 애플리케이션에서는 사용할 수 없습니다. 그러나 NativeAOT가 아닌 일반 애플리케이션을 게시하는 동안 미리 컴파일된 쿼리를 활용할 수 있습니다. 이를 통해 미리 컴파일된 쿼리가 제공하는 시작 시간 단축의 이점을 활용할 수 있으며, 현재 NativeAOT에서 지원되지 않는 동적 쿼리 및 기타 기능을 사용할 수 있습니다.
NativeAOT 없이 미리 컴파일된 쿼리를 사용하는 것은 다음을 실행하는 문제일 뿐입니다.
dotnet ef dbcontext optimize --precompile-queries
위와 같이 미리 컴파일될 수 있는 쿼리에 대해 컴파일된 모델 및 인터셉터를 생성하여 애플리케이션의 시작 시간에서 오버헤드를 제거합니다.
.NET