Entity Framework クエリパフォーマンス最適化の実践手法

基本的な最適化戦略

Entity Framework (EF) はデータアクセス層の開発効率を向上させますが、適切な設定がなければパフォーマンス低下を招きます。以下に主要な改善手法を解説します。

遅延ロードの制御

遅延ロードはデフォルトで有効ですが、不要な場合は無効化し、必要な関連データは明示的に取得します。

var context = new SchoolDbContext();
context.Configuration.LazyLoadingEnabled = false;

// 関連データを含めない場合
var students = context.Students.Take(10).ToList();

// 明示的に関連データを取得
var studentsWithClass = context.Students
    .Include(s => s.Class)
    .Take(10)
    .ToList();

トラッキング無効化による読み取り最適化

読み取り専用クエリではAsNoTrackingを活用し、オブジェクトトラッキングのオーバーヘッドを排除します。

var readOnlyStudents = context.Students
    .Where(s => s.Age > 18)
    .AsNoTracking()
    .ToList();

複数条件ソートの実装

複数カラムのソートではOrderByの連続使用ではなくThenByを適用します。

var sortedStudents = context.Students
    .OrderBy(s => s.LastName)
    .ThenBy(s => s.FirstName)
    .ToList();

SQL直接実行時の分頁処理

サーバー側で分頁処理を行い、メモリ内での処理を避けてください。

var sql = @"
    SELECT * FROM (
        SELECT *, ROW_NUMBER() OVER (ORDER BY CreatedAt DESC) AS RowNum
        FROM Students
    ) AS T
    WHERE RowNum BETWEEN 1 AND 20";
var pagedData = context.Database.SqlQuery<Student>(sql).ToList();

存在確認の効率化

存在チェックにはAnyメソッドを使用し、CountやFirstOrDefaultを避けてパフォーマンスを向上させます。

bool exists = context.Classes.Any(c => c.Name == "AdvancedClass");

複数テーブル結合の最適化

内結合と左外部結合の実装例を示します。

// 内結合
var innerJoin = context.Classes
    .Where(c => c.Budget > 2000)
    .Join(context.Students,
        c => c.Id,
        s => s.ClassId,
        (c, s) => new { ClassName = c.Name, StudentName = s.Name })
    .ToList();

// 左外部結合
var leftJoin = (from c in context.Classes
                join s in context.Students on c.Id equals s.ClassId into temp
                from s in temp.DefaultIfEmpty()
                select new { ClassName = c.Name, StudentName = s?.Name })
    .ToList();

動的クエリ生成

条件に応じた動的クエリ構築にはExpression拡張を利用します。

Expression<Func<Student, bool>> filter = s => true;
if (!string.IsNullOrEmpty(searchTerm)) {
    filter = filter.And(s => s.Name.Contains(searchTerm));
}
if (minAge > 0) {
    filter = filter.And(s => s.Age >= minAge);
}

var results = context.Students
    .Where(filter)
    .OrderBy(s => s.CreatedAt)
    .Skip(0)
    .Take(20)
    .ToList();

タグ: Entity-Framework csharp LINQ Database-Optimization query-performance

8月3日 20:34 投稿