EFCoreのDetectChangesを無効にしたらどれくらいInsertが速くなるのか?
はじめに
現在常駐しているお客様先の上司とお話していたところ、EFCore(Entity Framework Core)のDetectChangesというキーワードが出てきて何だそれは!!?という状態になったので調べてみました。
ChangeTracker.AutoDetectChangesEnabledプロパティ
EFCoreではデータベースの更新処理(Add, Update, Delete)があった際にDetectChanges()メソッドによる整合性チェック(MSのドキュメントでは変更の追跡という説明がされています)が行われます。
ここら辺は以下のサイトの説明がとても分かりやすかったです。
DetectChanges() の処理を簡単に言うと、DB から取得したデータと、現在のデータを比べて、変更があればデータのステータス EntityState を更新している。 しかし、DbSet
.Add や DbSet .Remove は、対象データのステータスを EntityState.Added や EntityState.Deleted に更新するので、DetectChanges() の実行は不要。
よってInsertやDeleteの際はChangeTracker.AutoDetectChangesEnabledをfalseにして実行してみると良さそうです。
サンプルコード
サンプルコードはPersonモデル情報をSQLiteへ数十万件Insertするパフォーマンスを調査する内容になっています。 カラムはPersonId, Name, Mail, Ageといたってシンプルな感じです。
public async Task<IActionResult> Create() { // DetectChangesをfalseにするかこちらで調整します。デフォルトはtrueです。 // _context.ChangeTracker.AutoDetectChangesEnabled = false; Stopwatch sw = new(); sw.Start(); // 今回は20万件のデータと50万件のデータで確認してみました。 for (var i = 0; i < 500000; i++) { var personData = new Person { Name = $"name{i + 1}", Mail = $"mailAddres{i + 1}", Age = i + 1 }; _context.Add(personData); } await _context.SaveChangesAsync(); sw.Stop(); TimeSpan ts = sw.Elapsed; ViewData["Elapsed"] = $"{ts.Seconds}秒{ts.Milliseconds}ミリ秒"; return View(); }
それぞれStopwatchクラスで時間をはかった結果以下のようになりました。
20万件 | 50万件 | |
---|---|---|
AutoDetectChangesEnabled = false | 13秒829ミリ秒 | 33秒310ミリ秒 |
AutoDetectChangesEnabled = true | 14秒562ミリ秒 | 35秒465ミリ秒 |
ふむふむ。たしかに変更の追跡がない分速度は速くなっています。 今回はそれほど大きくは変わっていないですが、データの形によっては大きく変わってくるのかな?
おわりに
Entity Frameworkについてもっと勉強して理解度を深めていけるように頑張ります!!!