2011-07-09 14 views
1

Entity Frameworkを使用して特定のオブジェクトのインスタンスをデータベースに挿入します。私はいくつかの 'Product'オブジェクトを添付する単一のオブジェクトコンテキストを持っています。私が挿入するオブジェクトは、データベース内の他のテーブルとは関係がありません。それは単なる単体です。私はアプリケーションをプロファイルするために 'EFProf'ツールを使用しています。Entity Frameworkのバルク挿入により、選択されたn + 1の問題が発生する

'Product'エンティティをSQL Serverに保存するために 'SaveChanges()'を呼び出すと、EFProfから 'Select N + 1'のパターンがないことが警告されます。私は単に挿入しているので、これがどのように可能であるかわかりません。私の「Select N + 1」の理解は、非効率的なオブジェクト検索に関連するということです。私は何かを取得していない、挿入するだけです。

生成されたSQLを調べると、Entity Frameworkが新しく挿入されたオブジェクトのIDを返すselect文を生成したことがわかります。このselect文は、挿入するすべてのエンティティに対して実行されます。これがN + 1選択問題の原因になりますか?もしそうなら、SaveChanges()への一回の呼び出しで同じタイプの多数のエンティティを挿入するときに、どのようにこのアンチパターンを避けることができますか?

生成されたSQL

は以下の通りです:

insert [dbo].[Products] 
    ([ProductName], 
    [ProductNum], 
    [Price], 
    [EntryDate], 
    [Description], 
    [Category], 
    [UnitsInStock]) 
values('TestProduct' /* @0 */, 
    0 /* @1 */, 
    0 /* @2 */, 
    '2011-07-09T17:14:49.00' /* @3 */, 
    'Category: Test Products - Name TestProduct' /* @4 */, 
    'Test Products' /* @5 */, 
    0 /* @6 */) 


select [Id] 
from [dbo].[Products] 
where @@ROWCOUNT > 0 
     and [Id] = scope_identity() 

答えて

1

。データベースで自動生成されたIDを使用し、モデルが正しく構成されていれば、EFは常にこの追加の選択を作成します。

あなたは気にする必要はありません。 EFでの "バルク挿入"のパフォーマンスは非常に悪く、挿入するたびにこの追加選択は何も意味しません。 EFは挿入されたレコードごとにデータベースへの個別のラウンドトリップを作成し、それが問題であるため、処理する必要があります。多数のオブジェクトをデータベースに渡したい場合は、頻繁に実行したい(1回の作業ではありません)、EF以外のソリューションを探す必要のあるパフォーマンスが期待されます。例えば、既に述べた通りSqlBulkCopy

いくつかの操作でいくつかのインスタンスを挿入するだけでよい場合は、そのまま使用してください。それがEFの仕組みです。

+0

本当に有用なコメントありがとうございます。私は今NHibernateとEntity Frameworkのパフォーマンステストを行っています。これは私が実行した最初のテストケースであり、NHibernateの結果は非常に高速で(バッチ処理なしでも)、自分のコードに何が間違っているのかがわかり始めています。私が見る限り、テストケースは同じように実装されています。一括挿入のEFパフォーマンスが「ひどく悪い」と言えば、これは何をベースにしていますか?非常に有用なこの問題を記述した他の研究や記事がある場合は、結果を書き留める必要があります。ありがとう。 – JMc

+0

それは簡単です。あなたのアプリケーションに関連オブジェクトを持つオブジェクトを作成するとします。たとえば、50個の注文アイテムで注文します。コマンドバッチングと呼ばれる機能がある場合(正しく使用されている場合、NHibernateはそれを持っています)、データベースへの1回のラウンドトリップを行い、51個の挿入(1桁、50桁)を含みます。あなたがEFで同じことをしているならば、それはそれぞれが単一の挿入物を含むデータベースに51の丸太を順次行います。往復は、あなたができるほとんどすべての操作の中で最も遅い部分です。 –

0

一括挿入を実行しようとしている場合、SCOPE_IDENTITY()は範囲ではなく1つのスカラー値を格納するため、役に立たないようです。私はEFの無知を裏切るつもりですが、このコードをBULK INSERTコマンドまたはSQLBulkCopyなどに変換していますか?

あなたは、代わりに句が一般的でより良いパターンであるように思わどこに置くの@@ROWCOUNT最初にチェックし、一度に一つのインサートをやろうとしている場合:

IF @@ROWCOUNT = 1 
BEGIN 
    SELECT [Id] 
     FROM [dbo].[Products] 
     WHERE [Id] = SCOPE_IDENTITY(); 
END 

か、まったく悩ま、以下の結果セットが空の場合以来、あなたは今@@ROWCOUNTが何であったかを知っている:あなたは追加の選択を回避することはできません

SELECT [Id] 
    FROM [dbo].[Products] 
    WHERE [Id] = SCOPE_IDENTITY(); 
関連する問題