HN 日本語サマリー

← 一覧へ戻る
プログラミング

EF Core 11でSplit Queryが高速化

EF Core 11 makes your split queries faster (steven-giesel.com)

58 pointsby rellem28 コメント

要約

EF Core 11では、`AsSplitQuery`機能におけるパフォーマンスの改善が行われました。以前のバージョンでは、参照ナビゲーションを含めるとコレクションクエリで不要なJOINが発生し、クエリが非効率になることがありました。EF Core 11では、これらの参照ナビゲーションをクエリから除外することで、SQLクエリが最適化され、実行速度の向上とメモリ使用量の削減が実現されています。

全文翻訳

目次 コードベースのどこかでAsSplitQueryを使用している場合、EF Core 11にはプレゼントがあります。それは、クエリが高速になることです。 デフォルトでは、EF Coreはすべてのデータを1つのクエリでロードします。コレクションをIncludeすると、それはJOINを意味し、コレクションに対するJOINは親行を子ごとに重複させます。より多くのものをJOINするほど、「悪化」します。 AsSplitQueryはそれを解決します。EFはルートエンティティ用のクエリと、追加のコレクションごとのクエリを実行します。 もちろん、これは万能薬ではなく、以下のような結果を招く可能性があります。 より多くのラウンドトリップ ルートエンティティと子エンティティの間で状態が変更される可能性(複数のトランザクションであるため、アトミックな操作ではありません)。 詳細はこちら: https://learn.microsoft.com/en-us/ef/core/querying/single-split-queries では、問題は何でしょうか?元の問題からのセットアップは次のとおりです。1つの参照ナビゲーション、1つのコレクションナビゲーションです。 var result = context.Blogs .Include(x => x.BlogType) // 参照ナビゲーション .Include(x => x.Posts) // コレクションナビゲーション .AsSplitQuery() .ToList(); EF Core 10まで、これは2つのクエリを生成していました。 SELECT [b].[Id], [b].[BlogDetailId], [b].[BlogTypeId], [b].[Name], [b0].[Id], [b0].[Type] FROM [Blogs] AS [b] LEFT JOIN [BlogType] AS [b0] ON [b].[BlogTypeId] = [b0].[Id] ORDER BY [b].[Id], [b0].[Id] SELECT [p].[Id], [p].[BlogId], [p].[Title], [b].[Id], [b0].[Id] FROM [Blogs] AS [b] LEFT JOIN [BlogType] AS [b0] ON [b].[BlogTypeId] = [b0].[Id] INNER JOIN [Post] AS [p] ON [b].[Id] = [p].[BlogId] ORDER BY [b].[Id], [b0].[Id] 2番目のクエリを見てください。Postsを取得するクエリです。なぜBlogTypeが含まれているのでしょうか?テーブルをJOINし、そのIdを選択し、それに基づいてORDER BYしています。これらはどれも必要ありません。PostをBlogに一致させるには、Blogの主キーがあれば十分です。 そして、参照ナビゲーションが増えるほど悪化します。参照ナビゲーションに5つのIncludeがあるとどうなるでしょうか?すべてのコレクションクエリは、5つのJOINと5つの追加のORDER BY列を引きずります。データベースは作業を行い、結果を破棄し、クエリプランに悪影響を与えます。 では、何が変わったのでしょうか?EF Core 11(プレビュー3以降)は、コレクションクエリから参照ナビゲーションを削除します。2番目のクエリは、手動で記述したであろうものになります。 SELECT [p].[Id], [p].[BlogId], [p].[Title], [b].[Id] FROM [Blogs] AS [b] INNER JOIN [Post] AS [p] ON [b].[Id] = [p].[BlogId] ORDER BY [b].[Id] ベンチマーク このブログ投稿の最後に、セットアップ全体のリンクを掲載します。ここでは、私が使用していた小さなセットアップを示します。上記のリンクされたGithubイシューで、ほぼ同じものを見つけることができます。 免責事項:EF 10(.net 10内)とEF 11(.net 11内)を比較しました。とはいえ、すべてのメリットがEF 11のみに起因するわけではない可能性があります。ベンチマークで2つの変数を変更したためです。理論的には、.net 10から.net 11への変更のみである可能性もありますが、可能性は低いです。 [MemoryDiagnoser] [SimpleJob(RuntimeMoniker.Net10_0)] [SimpleJob(RuntimeMoniker.Net11_0)] public class SplitQueryBenchmarks { private SqliteConnection _connection = null!; private DbContextOptions<BloggingContext> _options = null!; [GlobalSetup] public void Setup() { _connection = new SqliteConnection("Data Source=:memory:"); _connection.Open(); _options = new DbContextOptionsBuilder<BloggingContext>() .UseSqlite(_connection) .Options; using var context = new BloggingContext(_options); context.Database.EnsureCreated(); Seeder.Seed(context, blogCount: 5_000, postsPerBlog: 5); } [GlobalCleanup] public void Cleanup() => _connection.Dispose(); [Benchmark] public List<Blog> SplitQuery() { using var context = new BloggingContext(_options); return BlogQuery(context).AsSplitQuery().ToList(); } private static IQueryable<Blog> BlogQuery(BloggingContext context) => context.Blogs .AsNoTracking() .Include(b => b.Author) .Include(b => b.Category) .Include(b => b.Series) .Include(b => b.Posts); } 結果: | Method | Runtime | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated | |----------- |---------- |---------:|---------:|---------:|---------:|----------:|----------:|---------:|----------:| | SplitQuery | .NET 10.0 | 68.53 ms | 1.358 ms | 2.742 ms | 67.54 ms | 4375.0000 | 1000.0000 | 375.0000 | 33.35 MB | | SplitQuery | .NET 11.0 | 62.07 ms | 1.213 ms | 2.788 ms | 61.10 ms | 4111.1111 | 1333.3333 | 444.4444 | 30.15 MB | 実行時間と割り当てが減少しました! リソース このブログ投稿のソースコード:こちら 私のサンプルコードはすべてこのリポジトリでホストされています:こちら Githubイシュー:https://github.com/dotnet/efcore/issues/29182 1 コピー LinkedInで共有 Xで共有 Blueskyで共有 スポンサー 関連記事 EF Core 6 - 新機能 EF Core 6 はもうすぐ登場し、非常に有望に見えます。このブログ投稿では、どのような新機能が登場するかを紹介します。 7/12/2021 3 分の読み込み EF Core C# .NET 6 EF Core 6 私のEF LINQ to SQLクエリは安全ですか? EF LINQクエリがSQLインジェクション攻撃に対して脆弱かどうか、疑問に思ったことはありませんか?ユーザーデータをテキストフィールドからクエリしているか、APIがデータベースにヒットしたものを直接取得しているかのどちらかです。 6/17/2024 3 分の読み込み C# .NET Entity Framework EF .NET 11でのZstandard圧縮 .NETには、DeflateStream、GZipStream、ZLibStream、BrotliStreamがしばらく前からありました。.NET 11では、新しいものがパーティーに参加します。ZstandardStreamです。そして今、私たちは.NETで「Zstd」と言うことができます。 5/18/2026 2 分の読み込み .NET .NET 11