⚡ SQLパフォーマンスデモ

データベースアクセスの性能問題を体感できるデモ

N+1問題デモ

ORMでよく発生するN+1問題を実際に体験できるAPIエンドポイントです。

📚 N+1問題とは?

N+1問題は、ORMを使用する際に発生する典型的なパフォーマンス問題です:

  1. 1回目のクエリ: 親エンティティ(ユーザー)を取得 → 100件取得
  2. N回のクエリ: ループ内で各ユーザーの関連エンティティ(部署)を個別に取得 → 100回クエリ発行
  3. 合計: 1 + 100 = 101回のSQL発行 🐌

この問題は、Eager Loadingで解決できます:

  • Bad: Users.ToListAsync() → ループで Departments.Find(id)
  • Good: Users.Include(u => u.Department).ToListAsync() → 1回のJOINクエリ ⚡

🔌 エンドポイント

エンドポイント 説明 クエリ数 アクション
GET /api/demo/n-plus-one/bad N+1問題あり(非効率) 101回
GET /api/demo/n-plus-one/good 最適化済み(効率的) 1回

💻 実行結果

🔍 性能比較

メトリクス Bad (N+1) Good (Eager Loading) 改善率
SQL発行回数 101回 1回 99%削減
実行時間 ~45ms ~12ms 73%高速化

注意: InMemoryデータベースのため実行時間差は小さいですが、SQL Serverでは数十倍の差が出ることもあります。

🎓 学習ポイント

このデモでは以下を学べます:

  1. N+1問題の発生原因: ループ内での個別クエリ発行
  2. 解決方法: Entity Framework CoreのInclude()によるEager Loading
  3. 性能測定: SQL発行回数と実行時間の比較

実装例

Bad: N+1問題あり
// Bad: N+1問題あり
var users = await context.Users.ToListAsync();
foreach (var user in users) {
    var dept = await context.Departments
        .FindAsync(user.DepartmentId);
}
Good: 最適化済み
// Good: 最適化済み
var users = await context.Users
    .Include(u => u.Department)
    .ToListAsync();

⚙️ SQL Server向けセットアップ(オプション)

本番環境でSQL Serverを使用する場合は、以下のSQLファイルを実行してください:

# 1. テーブル作成
sqlcmd -S your-server -d your-database -i sql/demo/n-plus-one/01_ddl.sql

# 2. ダミーデータ投入(100ユーザー、10部署)
sqlcmd -S your-server -d your-database -i sql/demo/n-plus-one/02_insert.sql

デフォルト設定: InMemoryデータベースを使用しているため、SQLファイルの実行は不要です。アプリケーション起動時に自動的にダミーデータが生成されます。