【Entity Framework Core】レコード追加と性能比較
Entity Framework Core によるレコード追加方法と性能比較結果を記載します。
レコードの追加(AddおよびAddRange)
AddメソッドおよびAddRangeメソッドでレコード追加する例を記載します。
Addメソッド
Addメソッドで単一エンティティを設定して、SaveChangeメソッドを実行します。
するとデータベースにレコードを追加するSQLが発行されます。
するとデータベースにレコードを追加するSQLが発行されます。
コード例
using (var context = new MyDBContext())
{
var product = new Product { Id = 1, Name = "Name1", Price = 1000, CategoryId = 10 };
context.Products.Add(product);
context.SaveChanges();
}
発行されるSQL
Addメソッドで設定した単一エンティティ登録するINSERT文が発行されます。
[Parameters=[@p0='1', @p1='10', @p2='Name1' (Nullable = false) (Size = 50), @p3='1000'],
CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
INSERT INTO [Products] ([Id], [CategoryId], [Name], [Price])
VALUES (@p0, @p1, @p2, @p3);
次はAddメソッドで複数の単一エンティティを設定して、SaveChangeメソッドを実行します。
コード例
using (var context = new MyDBContext())
{
var product = new Product { Id = 1, Name = "Name1", Price = 1000, CategoryId = 10 };
var product = new Product { Id = 2, Name = "Name2", Price = 2000, CategoryId = 20 };
var product = new Product { Id = 3, Name = "Name3", Price = 3000, CategoryId = 30 };
context.Products.Add(product);
context.SaveChanges();
}
発行されるSQL
Addメソッドで設定した複数の単一エンティティを一度に登録するINSERT文が発行されます。
[Parameters=[@p0='1', @p1='10', @p2='Name1' (Nullable = false) (Size = 50), @p3='1000',
@p4='2', @p5='20', @p6='Name2' (Nullable = false) (Size = 50), @p7='2000',
@p8='3', @p9='30', @p10='Name3' (Nullable = false) (Size = 50), @p11='3000'],
CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
INSERT INTO [Products] ([Id], [CategoryId], [Name], [Price])
VALUES (@p0, @p1, @p2, @p3),
(@p4, @p5, @p6, @p7),
(@p8, @p9, @p10, @p11);
AddRangeメソッド
AddRangeメソッドで複数エンティティを設定して、SaveChangeメソッドを実行します。
するとデータベースにレコードを追加するSQLが発行されます。
するとデータベースにレコードを追加するSQLが発行されます。
コード例
using (var context = new MyDBContext())
{
var products = new List<Product>();
products.Add(new Product { Id = 1, Name = "Name1", Price = 1000, CategoryId = 10 });
products.Add(new Product { Id = 2, Name = "Name2", Price = 2000, CategoryId = 20 });
products.Add(new Product { Id = 3, Name = "Name3", Price = 3000, CategoryId = 30 });
context.Products.AddRange(products);
context.SaveChanges();
}
発行されるSQL
AddRangeメソッドで設定した複数エンティティを一度に登録するINSERT文が発行されます。
するとデータベースにレコードを追加するSQLが発行されます。
するとデータベースにレコードを追加するSQLが発行されます。
[Parameters=[@p0='1', @p1='10', @p2='Name1' (Nullable = false) (Size = 50), @p3='1000',
@p4='2', @p5='20', @p6='Name2' (Nullable = false) (Size = 50), @p7='2000',
@p8='3', @p9='30', @p10='Name3' (Nullable = false) (Size = 50), @p11='3000'],
CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
INSERT INTO [Products] ([Id], [CategoryId], [Name], [Price])
VALUES (@p0, @p1, @p2, @p3),
(@p4, @p5, @p6, @p7),
(@p8, @p9, @p10, @p11);
アタッチによるレコード追加(AttachおよびAttachRange)
AttachメソッドおよびAttachRangeメソッドでエンティティをアタッチしてレコード追加する例を記載します。
Attachメソッド
Attachメソッドで単一エンティティをアタッチしたあとに、EntityState.Addedで追加状態にして、SaveChangeメソッドを実行します。
するとデータベースにレコードを追加するSQLが発行されます。
するとデータベースにレコードを追加するSQLが発行されます。
コード例
using (var context = new MyDBContext())
{
var product = new Product { Id = 1, Name = "Name1", Price = 1000, CategoryId = 10 };
context.Products.Attach(product);
context.Entry(product).State = EntityState.Added;
context.SaveChanges();
}
発行されるSQL
Attachメソッドで設定した単一エンティティ登録するINSERT文が発行されます。
[Parameters=[@p0='1', @p1='10', @p2='Name1' (Nullable = false) (Size = 50), @p3='1000'],
CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
INSERT INTO [Products] ([Id], [CategoryId], [Name], [Price])
VALUES (@p0, @p1, @p2, @p3);
AttachRangeメソッド
AttachRangeメソッドで複数エンティティをアタッチしたあとに、EntityState.Addedで追加状態にして、SaveChangeメソッドを実行します。
するとデータベースにレコードを追加するSQLが発行されます。
するとデータベースにレコードを追加するSQLが発行されます。
コード
using (var context = new MyDBContext())
{
var products = new List<Product>();
products.Add(new Product { Id = 1, Name = "Name1", Price = 1000, CategoryId = 10 });
products.Add(new Product { Id = 2, Name = "Name2", Price = 2000, CategoryId = 20 });
products.Add(new Product { Id = 3, Name = "Name3", Price = 3000, CategoryId = 30 });
context.Products.AttachRange(products);
foreach (var product in products)
{
context.Entry(product).State = EntityState.Added;
}
context.SaveChanges();
}
発行SQL
AttachRangeメソッドで設定した複数エンティティを一度に登録するINSERT文が発行されます。
[Parameters=[@p0='1', @p1='10', @p2='Name1' (Nullable = false) (Size = 50), @p3='1000',
@p4='2', @p5='20', @p6='Name2' (Nullable = false) (Size = 50), @p7='2000',
@p8='3', @p9='30', @p10='Name3' (Nullable = false) (Size = 50), @p11='3000'],
CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
INSERT INTO [Products] ([Id], [CategoryId], [Name], [Price])
VALUES (@p0, @p1, @p2, @p3),
(@p4, @p5, @p6, @p7),
(@p8, @p9, @p10, @p11);
BulkInsert
BulkInsertメソッドで複数エンティティを一括挿入することでレコードを追加します。SaveChangeメソッドは不要です。
コード例
using EFCore.BulkExtensions;
using (var context = new MyDBContext())
{
var products = new List<Product>();
products.Add(new Product { Id = 1, Name = "Name1", Price = 1000, CategoryId = 10 });
products.Add(new Product { Id = 2, Name = "Name2", Price = 2000, CategoryId = 20 });
products.Add(new Product { Id = 3, Name = "Name3", Price = 3000, CategoryId = 30 });
context.BulkInsert(products);
}
パッケージのインストール
BulkInsertメソッドを使用するにはEFCore.BulkExtensionsパッケージのインストールが必要です。
メニューから[ツール]>[Nugetパッケージマネージャー]>[パッケージマネージャーコンソール]を開き以下のコマンドを実行します。
メニューから[ツール]>[Nugetパッケージマネージャー]>[パッケージマネージャーコンソール]を開き以下のコマンドを実行します。
Install-Package EFCore.BulkExtensions
性能比較
レコード追加方法ごとに性能測定した結果を記載します。
- 計測環境
- 処理内容
- 計測結果
OS:Windows10(64-bit) RAM:16.0GB CPU:Core i7
.Net7
Entity Framework Core Version 7.0.3
Microsoft SQL Server 2022 Developer Edition (64-bit)
100万件のレコードを追加します。
5回計測した結果の中央値を記載しています。
計測メソッド | 処理時間(秒) |
---|---|
Add | 80.132 |
AddRange | 68.281 |
Attach | 82.977 |
AttachRange | 67.674 |
BulkInsert | 12.269 |
BulkInsertが他のメソッドより圧倒的に早い結果となりました。
AddとAddRangeでは複数エンティティを設定するAddRangeのほうが早い結果となりました。
DBコンテキストにエンティティを設定する際に、Addは1つずつ追加するためAddRangeと比較して遅いと考えられます。SaveChangeのあとにデータベース発行されるINSERT文は、どちらも複数エンティティを一括登録してます。
AttachとAttachRangeも同様に複数エンティティを設定するAttachRangeのほうが早い結果となりました。こちらの結果も同様の理由であると考えれます。
AddとAddRangeでは複数エンティティを設定するAddRangeのほうが早い結果となりました。
DBコンテキストにエンティティを設定する際に、Addは1つずつ追加するためAddRangeと比較して遅いと考えられます。SaveChangeのあとにデータベース発行されるINSERT文は、どちらも複数エンティティを一括登録してます。
AttachとAttachRangeも同様に複数エンティティを設定するAttachRangeのほうが早い結果となりました。こちらの結果も同様の理由であると考えれます。