Entity Frameworkが遅すぎる。私のオプションは何ですか?[閉まっている]


93

「時期尚早に最適化しない」というマントラに従い、Entity Frameworkを使用してWCFサービスをコーディングしました。

しかし、私はパフォーマンスのプロファイルを作成しましたが、Entity Frameworkは遅すぎます。(私のアプリは約1.2秒で2つのメッセージを処理しますが、私が書き直している(レガシー)アプリは同時に5〜6つのメッセージを処理します(レガシーアプリはDBアクセスのためにsprocsを呼び出します)。

私のプロファイリングは、Entity Frameworkがメッセージごとに大部分の時間を費やしていることを示しています。

それで、私の選択肢は何ですか?

  • より良いORMはありますか?
    (オブジェクトの通常の読み取りと書き込みをサポートし、それを高速に実行するもの。)

  • Entity Frameworkを高速化する方法はありますか?
    :速く言うと、最初の呼び出しではなく、長期的に意味します(最初の呼び出しは遅い(メッセージの場合15秒))が、それは問題ではありません。メッセージの。)

  • サービスの速度を上げるのに役立ついくつかの神秘的な3番目のオプション。

注:私のDBインタラクションのほとんどは作成と更新です。選択と削除はほとんど行いません。


これは、「linqが遅い」のリハッシュのように聞こえますが、それがEFであることをどのようにして知っていますか?すべての変更をプロファイルしましたか?
Maess

6
一部の回答はクエリを指しています。私の経験では、EFの遅さはクエリとはほとんど関係ありませんが、代わりに具体化のコストに関係しています。これらのコストは、変更の追跡と、作成されたインスタンスにどのように影響するかと関連していることがよくあります。残念ながら、私には特効薬はありませんので、これは単なるコメントですが、プロファイリングによって実体化コストが高くなるかどうかを確認し、そうであれば、そのコストについて何ができるかを調査することをお勧めします。
Anthony Pegram 2011

@Maess-プロファイルを作成したことを示したところ、EF / DBが遅いことがわかりました。いずれにせよ、そうです。私はそれをプロファイルしました、そしてそれは主要な犯人であるEF / DB相互作用です。
Vaccano

@Anthony-実体化は最初のようなものではありませんか?もしそうなら、あなたはそれが非常に遅いのは正しいです。最初の実行は非常に遅いです。しかし、私が示したように、私はそれについてあまり心配していません。問題となるのは総スループットです。(
マテリアライゼーション

1
@Vaccano、いいえ、実体化とは、データベースからデータを取得し、そのデータを表すためにオブジェクトのグラフをインスタンス化してデータを取り込むプロセスです。コードがjitterされているため(またはSQL Serverがクエリ実行プランを作成している場合でも)、最初の実行のパフォーマンスについては話していませんが、オブジェクトの形式でデータを取得するたびに何が起こるかを説明します。
Anthony Pegram 2011

回答:


46

Entity Frameworkによって実際に発行されたSQLコマンドをプロファイリングすることから始めるべきです。構成(POCO、自己追跡エンティティ)によっては、最適化の余地がたくさんあります。ObjectSet<T>.ToTraceString()メソッドを使用してSQLコマンドをデバッグできます(デバッグモードとリリースモードで違いはありません)。さらに最適化が必要なクエリが発生した場合は、いくつかの予測を使用して、EFが達成しようとしていることに関する詳細な情報を提供できます。

例:

Product product = db.Products.SingleOrDefault(p => p.Id == 10);
// executes SELECT * FROM Products WHERE Id = 10

ProductDto dto = new ProductDto();
foreach (Category category in product.Categories)
// executes SELECT * FROM Categories WHERE ProductId = 10
{
    dto.Categories.Add(new CategoryDto { Name = category.Name });
}

置き換えることができます:

var query = from p in db.Products
            where p.Id == 10
            select new
            {
                p.Name,
                Categories = from c in p.Categories select c.Name
            };
ProductDto dto = new ProductDto();
foreach (var categoryName in query.Single().Categories)
// Executes SELECT p.Id, c.Name FROM Products as p, Categories as c WHERE p.Id = 10 AND p.Id = c.ProductId
{
    dto.Categories.Add(new CategoryDto { Name = categoryName });
}

私は頭からそれを入力したので、これは正確に実行される方法ではありませんが、EFは実際にクエリについて知っているすべてを伝えると、いくつかの素晴らしい最適化を実行します(この場合、カテゴリが必要になります-名前)。ただし、プロジェクションはロードするデータの量をさらに削減できるため、これは熱心なロード(db.Products.Include( "Categories"))とは異なります。


40
匿名型は、それらが定義されているメソッドの外部からはアクセスできないことに気づくまで、この応答は妥当に聞こえます。巨大なオブジェクトを書き込まずに複雑なオブジェクトをロードする場合は、新しい匿名型をある種のPOCOに逆シリアル化する必要があります。繰り返しますが、そうすることで本質的に自分のエンティティのフレームワークを書き直していることに気づくまで、それはほとんど合理的に聞こえます。でたらめです。
Doug

5
これにより、速度が15倍から20倍に向上しました。
Dave Cousineau 2013年

11
興味深く、役立つ返事は、しばらくしてまだ有効です。@Doug:(予測を使用して)本当に必要ないくつかのクエリのみを最適化(予測を使用)するので、これは実際には大したことではありません。EFとPOCOは適切なデフォルトを提供します。
ビクター

2
@Dougほとんどのアプリケーションには、ビューのみのシナリオ用のビューモデルがありますよね?データを引き出すのと同じくらい多くのマッピングを行うかもしれません。
ケーシー

4
私はORMが未来であると感じていました。私がそれらを使い始めるまで、それらは理にかなっています。それから私はダッパーを見つけました。さて、このような解決策を見ると、複雑さが急速に高まっていることに私はうんざりしています。C#で抽象化されたSQLを作成することは、人生を歩む方法ではありません。
マイケルシルバー

80

問題の事実は、Entity Frameworkのような製品は、より多くのコードを実行しているため、常に低速で非効率的であることです。

また、LINQクエリの最適化、生成されたSQLの確認、デバッガーの使用、プリコンパイル、追加の手順の実行など、多くの時間を浪費することを人々が提案しているのもばかげています。誰も言うことはありません-簡素化!誰もがさらに多くのステップ(時間を無駄にすること)を行うことで物事をさらに複雑にしたいと考えています。

常識的なアプローチは、EFやLINQをまったく使用しないことです。プレーンSQLを使用します。何も問題はありません。プログラマーの間に群衆の考え方があり、彼らがそこにあるすべての新製品を使用したいという衝動を感じたからといって、それが良いことやうまくいくことを意味するのではありません。ほとんどのプログラマーは、大企業からリリースされたすべての新しいコードを組み込むと、より賢いプログラマーになると考えています。まったく真実ではありません。スマートプログラミングは、頭痛や不確実性を減らし、最短時間でより多くのことを行う方法に関するものです。覚えておいて-時間!それが最も重要な要素なので、単に奇妙ないわゆる「パターン」に準拠するように書かれた、不良/肥大化したコードの問題を解決するためにそれを無駄にしない方法を見つけてください

リラックスして、人生を楽しみ、コーディングから一休みして、追加の機能、コード、製品、「パターン」の使用を停止してください。寿命は短く、コードの寿命はさらに短く、確かにロケット科学ではありません。LINQやEFなどのレイヤーを削除すると、コードが効率的に実行され、スケーリングされます。そうすれば、維持も簡単になります。抽象化が多すぎると、悪い「パターン」になります。

そして、それがあなたの問題の解決策です。


155
これは赤ちゃんを風呂水で捨てます。ボトルネックを最適化します。いくつかの場所ではEFが遅すぎるため、他のほとんどの場所では高速であるため、EFをスローするのはばかげています。両方を使用しないのはなぜですか?EFは、ストアドプロシージャとraw SQLを適切に処理します。10秒以上かかったLINQ-to-SQLクエリを、約1秒かかるSPに変換しましたが、すべてのLINQ-to-SQLを破棄するつもりはありません。他の単純なケースでは時間を大幅に節約でき、コードも少なく、エラーの余地も少なくなり、クエリはコンパイラで検証され、データベースと一致します。コードが少ないほど、メンテナンスが容易になり、エラーの余地が少なくなります。
JulianR

11
全体的にあなたのアドバイスは良いものですが、EFや他の抽象化は10%の確率でうまく機能しないため、放棄することは適切ではないと思います。
JulianR、2011

49
プレーンSQL =保守が簡単ですか?多くのビジネスロジックを備えた非常に大規模なアプリには当てはまりません。複雑で再利用可能なSQLを書くのは簡単なことではありません。個人的に私はEFでいくつかのパフォーマンスの問題を抱えていましたが、これらの問題は、RADと物事をドライに保つという点で適切なORMの利点に単純には匹敵しません(複雑なレベルがある場合)。
MemeDeveloper 2012年

13
+ 10 ^ 100抽象化が多すぎると、悪い「パターン」になります
Makach

57
-1。「EFは常に遅く、非効率的です。」なぜあなたがこのようなものを絶対的な真実であると主張するのか分かりません。通過するレイヤーが多いと速度が低下しますが、その違いが顕著であるかどうかは、実行されるデータの量やクエリの種類などの状況に完全に依存します。私にとって、これはC ++よりも抽象度が高いため、「C#は常に遅くて非効率的だ」と同じことです。しかし、生産性の向上がパフォーマンスの低下(存在する場合)をはるかに上回るため、多くの人がそれを使用することを選択します。同じことがEFにも適用されます
Despertar

37

1つの提案は、単一レコードのCRUDステートメントに対してのみLINQ to Entity Frameworkを使用することです。

より複雑なクエリ、検索、レポートなどについては、ストアドプロシージャを記述し、MSDNで説明さているよう Entity Frameworkモデルに追加します。

これは私がいくつかのサイトで採用したアプローチであり、生産性とパフォーマンスのバランスが取れているようです。Entity Frameworkは常に、目前のタスクに対して最も効率的なSQLを生成するわけではありません。そして、理由を理解するために時間を費やすのではなく、より複雑なクエリのストアドプロシージャを作成することで、実際に時間を節約できます。プロセスに慣れたら、EFモデルにストアドプロシージャを追加するのはそれほど面倒ではありません。そしてもちろん、モデルに追加することの利点は、ORMを使用することから得られる、強く型付けされたすべての優れた機能を利用できることです。


db.athlete.find(id)などのスキャフォールディングで使用されるメソッドについてのアイデアはありますか?ADO.NETまたはdapperと比較して、それらはどのように機能しますか?
それはトラップである

15

あなたはしている場合は、純粋データをフェッチし、それはあなたがそれをフェッチするエンティティを追跡しないようにEFを伝えるパフォーマンスに大きな助けです。これを行うには、MergeOption.NoTrackingを使用します。EFはクエリを生成して実行し、結果をオブジェクトに逆シリアル化しますが、エンティティの変更やそのような性質の追跡を試みません。クエリが単純な場合(データベースが返されるのを待機するのに多くの時間を費やさない場合)、クエリをNoTrackingに設定するとクエリのパフォーマンスが2倍になることがわかりました。

MergeOption列挙型に関するこのMSDNの記事を参照してください。

ID解決、状態管理、および変更の追跡

これはEFパフォーマンスに関する良い記事のようです:

パフォーマンスとエンティティフレームワーク


9
誰かがこれを行う前に、ここで読むことをお勧めします。stackoverflow.com/questions/9259480/...
leen3o

6

アプリケーションのプロファイルを作成したと言います。ORMのプロファイルも作成しましたか?AyendeのEFプロファイラーがあり、EFコードを最適化できる場所を強調しています。あなたはそれをここで見つけることができます:

http://efprof.com/

パフォーマンスを向上させる必要がある場合は、ORMと一緒に従来のSQLアプローチを使用できます。

より速い/より良いORMがある場合?オブジェクト/データモデルによっては、DapperMassivePetaPocoなどのいずれかのマイクロORMの使用を検討できます。

Dapperのサイトでは、他のORMと比較する方法を理解できるいくつかの比較ベンチマークを公開しています。ただし、マイクロORMがEFやNHなどの完全なORMの豊富な機能セットをサポートしていないことは注目に値します。

あなたは見て撮りたいかもしれRavenDBを。これは非リレーショナルデータベースであり(Ayendeから)、マッピングを必要とせずにPOCOを直接格納できます。RavenDBは読み取り用に最適化されており、スキーマを操作したり、オブジェクトをそのスキーマにマップしたりする必要がなくなるため、開発者の作業がずっと簡単になります。ただし、これはORMアプローチを使用する場合とは大きく異なるアプローチであり、これらは製品のサイトで概説されていることに注意してください。


3

私はここで @Slaumaによる答えが物事をスピードアップするのに非常に役立つことを発見しました。挿入と更新の両方で同じ種類のパターンを使用しました-パフォーマンスは急上昇しました。


2

私の経験から、問題はEFではなく、ORMアプローチ自体にあります。

一般に、すべてのORMは、最適化されたクエリなどではなくN + 1の問題に悩まされています。私の推測では、パフォーマンスの低下を引き起こすクエリを追跡し、ORMツールを調整するか、SPROCでその部分を書き直すことです。


1
人々は私にこれを言い続けます。しかし、私は古い学校のADOを使用して単純な選択ステートメントを設定します。EFコンテキストとEFを使用した同じ単純な選択は常にかなり遅くなります。私は本当にEFが好きになりたいですが、それは人生をより簡単にするのではなく、より困難にし続けています。
Sinaesthetic 2014年

1
@Sinaestheticもちろん遅いです。同様に、Linq to Objectsを使用して記述されたコードは、それを使用せずに記述されたコードよりも通常遅くなります。問題は、それがより高速であるか、それとも同じくらい高速であるかではありませ(内部でまだ手動で発行していたクエリを発行する必要がある場合、どうすればよいでしょうか)。コードを書く時間3)利点はコストを相殺します。これらの項目に基づいて、EFは多くのプロジェクトに適していると思います。
ケーシー

@Sinaestheticまた、ORMを使用しない場合、多くの場合、SQLクエリがそれぞれ微調整および最適化されているのではなく、アプリケーションが社内で有機的で不十分に開発されていることも付け加えておきます。 -サポートされている、パフォーマンスの低いORM。ただし、チームが非常に規律があり、パフォーマンスに非常に関心がある場合を除きます。
ケーシー


1

私もこの問題に遭遇しました。EFはうまく機能するので、ダンプするのは嫌ですが、遅いだけです。ほとんどの場合、レコードを検索するか、更新/挿入するだけです。このような単純な操作でも遅いです。1100レコードをテーブルからリストにプルバックし、EFでその操作に6秒かかりました。私にとってこれは長すぎます。保存でさえも時間がかかりすぎます。

自分でORMを作ってしまいました。同じ1100レコードをデータベースからプルし、ORMに2秒かかりました。EFよりもはるかに高速です。私のORMのすべてはほとんど瞬時です。現時点での唯一の制限は、MS SQL Serverでのみ機能することですが、Oracleのような他の機能で動作するように変更することができます。今はすべてにMS SQL Serverを使用しています。

私のORMを試してみたい場合は、ここにリンクとウェブサイトがあります。

https://github.com/jdemeuse1204/OR-M-Data-Entities

または、ナゲットを使用する場合:

PM>インストールパッケージOR-M_DataEntities

ドキュメントもそこにあります


0

プロファイルを作成した後で最適化するのが理にかなっています。DBアクセスが遅いことがわかった場合は、ストアドプロシージャの使用に変換してEFを維持できます。EF自体が遅いことがわかった場合は、別のORMに切り替えるか、ORMをまったく使用しないことが必要な場合があります。


0

毎秒120リクエストを簡単に実行する同様のアプリケーション(Wcf-> EF->データベース)があるので、ここではEFが問題ではないと確信しています。つまり、コンパイルされたクエリでパフォーマンスが大幅に向上しました。


私のコードの98%はCreateおよびUpdate呼び出しです。それが違いを生むかどうかはわかりませんが、毎秒120よりもはるかに遅いです。
Vaccano

ええ、それは典型的なアプリケーションではありません。あなたのアプリケーションをプロファイルすることをお勧めします。私たちにとっては、ほとんどの場合...
np-hard

0

私はEF、LINQ to SQL、dapperを使用しました。ダッパーが最速です。例:それぞれに4つのサブレコードを持つ1000のメインレコードが必要でした。LINQ to sqlを使用した場合、約6秒かかりました。次に、dapperに切り替えて、単一のストアドプロシージャから2つのレコードセットを取得し、各レコードにサブレコードを追加しました。合計時間1秒。

また、ストアドプロシージャはクロス適用でテーブル値関数を使用しましたが、スカラー値関数は非常に遅いことがわかりました。

私のアドバイスは、EFまたはLINQ to SQLを使用し、特定の状況ではdapperに切り替えることです。


-1

Entity Framework自体が大きなボトルネックになることはありません。他の原因がある可能性があります。あなたはEFをLinq2SQLに切り替えることを試みることができます、どちらも比較機能を持ち、コードは簡単に変換できるはずですが、多くの場合、Linq2SQLはEFより高速です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.