⚡ SQLパフォーマンスデモ
データベースアクセスの性能問題を体感できるデモ
N+1問題デモ
ORMでよく発生するN+1問題を実際に体験できるAPIエンドポイントです。
📚 N+1問題とは?
N+1問題は、ORMを使用する際に発生する典型的なパフォーマンス問題です:
- 1回目のクエリ: 親エンティティ(ユーザー)を取得 → 100件取得
- N回のクエリ: ループ内で各ユーザーの関連エンティティ(部署)を個別に取得 → 100回クエリ発行
- 合計: 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では数十倍の差が出ることもあります。
🎓 学習ポイント
このデモでは以下を学べます:
- N+1問題の発生原因: ループ内での個別クエリ発行
- 解決方法: Entity Framework CoreのInclude()によるEager Loading
- 性能測定: 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ファイルの実行は不要です。アプリケーション起動時に自動的にダミーデータが生成されます。