web-dev-qa-db-ja.com

直接選択ステートメントでEntity FrameworkがDapperより高速に実行される理由

データベースの処理にORMを使用するのは初めてです。現在、新しいプロジェクトを作成しています。EntityFrameworkとDapperのどちらを使用するかを決定する必要があります。 DapperはEntity Frameworkよりも高速であるという記事をたくさん読みました。

そこで、2つの単純なプロトタイププロジェクトを作成しました。1つはDapperを使用し、もう1つは1つの関数でEntity Frameworkを使用して、1つのテーブルからすべての行を取得します。次の図のようなテーブルスキーマ

Table Schema

そして、次のように両方のプロジェクトのコード

dapperプロジェクト用

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
IEnumerable<Emp> emplist = cn.Query<Emp>(@"Select * From Employees");
sw.Stop();
MessageBox.Show(sw.ElapsedMilliseconds.ToString());

entity Frameworkプロジェクト用

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
IEnumerable<Employee> emplist = hrctx.Employees.ToList();
sw.Stop();
MessageBox.Show(sw.ElapsedMilliseconds.ToString());

プロジェクトを初めて実行するときにのみ上記のコードを何度も試した後、dapperコードは速くなり、エンティティフレームワークプロジェクトから常により良い結果が得られますエンティティフレームワークプロジェクトで次のステートメントを試して怠zyを停止しました積み込み

hrctx.Configuration.LazyLoadingEnabled = false;

ただし、同じEFのパフォーマンスは最初を除いて高速です。

このサンプルでEFを高速化するものについて、誰でも説明やガイダンスを提供できますか?

更新

エンティティサンプルのコード行を次のように変更しました

IEnumerable<Employee> emplist = hrctx.Employees.AsNoTracking().ToList();

いくつかの記事で言及されているAsNoTrackingを使用すると、エンティティフレームワークのキャッシュが停止し、キャッシュを停止した後、dapperサンプルのパフォーマンスが向上します(ただし、大きな違いはありません)

26
Ahmed

ORM(オブジェクトリレーショナルマッパー)は、アプリケーションとデータソースの間にレイヤーを作成し、ADO.NETオブジェクトの代わりに(使用しているc#に関して)リレーショナルオブジェクトを返すツールです。これは、すべてのORMが行う基本的なことです。

これを行うために、ORMは通常、クエリを実行し、map POCOクラスに返されたDataReaderを実行します。 Dapperはここまでに制限されています。

これをさらに拡張するために、一部のORM(「フルORM」とも呼ばれます)は、アプリケーションデータベースを独立させるためのクエリの生成、将来の呼び出しのためのデータのキャッシュ、作業単位の管理など、はるかに多くのことを行います。これらはすべて優れたツールであり、ORMに価値を追加します。しかし、それは費用がかかります。 Entity Frameworkはこのクラスに分類されます。

クエリを生成するには、EFは追加のコードを実行する必要があります。キャッシュはパフォーマンスを向上させますが、キャッシュを管理するには追加のコードを実行する必要があります。作業ユニットおよびEFが提供するその他のアドオン機能についても同様です。これはすべて節約されますyo追加のコードを書くとEFがコストを支払います。

そして、コストはパフォーマンスです。 Dapperは非常に基本的な作業を行うため、より高速です。ただし、さらにコードを記述する必要があります。 EFはそれ以上のことを行うため、(ビット)遅くなります。しかし、より少ないコードを書く必要があります。

だからあなたのテストが反対の結果を示す理由?
実行しているテストは比較できないためです。

上記で説明したように、フルORMには多くの優れた機能があります。それらの1つはUnitOfWorkです。追跡はUoWの責任の1つです。オブジェクトが最初に要求されると(SQLクエリ)、データベースへのラウンドトリップが発生します。このオブジェクトは、メモリキャッシュに保存されます。完全なORMは、この既にロードされたオブジェクトに加えられた変更を追跡します。同じオブジェクト(ロードされたオブジェクトを含む同じUoWスコープ内の他のSQLクエリ)が再度要求された場合、データベースの往復は行われません。代わりに、代わりにメモリキャッシュからオブジェクトを返します。これにより、かなりの時間が節約されます。
Dapperは、テストの実行速度を低下させるこの機能をサポートしていません。

ただし、この利点は、同じオブジェクトが複数回ロードされた場合にのみ適用されます。また、メモリにロードされたオブジェクトの数が多すぎる場合、メモリ内のオブジェクトをcheckするために必要な時間として代わりに、ORM全体が遅くなります高くなります。繰り返しますが、この利点はユースケースに依存します。

34
Amit Joshi

I read many articles which says that Dapper is faster than Entity Framework

インターネット上のほとんどのベンチマークの問題は、EF LinqとDapperを比較していることです。そして、それもあなたがしたことです。これは不公平です。多くの場合、自動生成されたクエリ(EF)は、優秀な開発者が作成したクエリとは異なります。

これ、

IEnumerable<Employee> emplist = hrctx.Employees.ToList();

これに置き換える必要があります。

IEnumerable<Employee> emplist = hrctx.Employees.FromSql(@"Select * From Employees").AsNoTracking();

編集:

@mjwillsが指摘したように、以下はinsertupdate、およびselectステートメントの結果テーブルです。

enter image description here

DapperはEF Core 2よりも優れています。ただし、EFプレーンクエリの場合、その差は非常に小さいことがわかります。 詳細はこちら を投稿しました。

5
Mohsin

記事 Entity Framework Core 2.0 vs. Dapperパフォーマンスベンチマーク、SQL Azureテーブルのクエリ は、Dapperが少し高速であることを確認しますが、「完全なORM」の利点を無視するには不十分です。

1

それらを一緒に混ぜても問題はありません。現在のプロジェクトでは、データの選択にDapperを使用し、データベースの移行と作成と更新にEFを使用しています。

Dapperは、3つ以上のテーブルが関係する複雑なクエリや、複数の列で結合する、> =および<=句で結合する、再帰選択、cteなど)複雑なクエリに関して非常に役立ちます純粋なSQLはLINQよりもはるかに簡単です。私が知っているように、Entity Framework(Dapperとは異なり)は、カスタムDTOで.FromSql()メソッドを使用できません。データベースコンテキスト内にある必要があるテーブルを1つだけマップできます。

1
Liam Kernighan