EntityFramework5とOracleDBでパフォーマンスの問題があります。
単純なSQL選択があります:SELECT * FROM NOTE WHERE NOTENUMBER = '1A23456'
NOTENUMBER
NOTEというテーブルのインデックスに含まれていますが、フィールドは主キー/一意ではありません。
Oracle SQL Developerを使用してステートメントを実行すると、結果がすぐに返され、クエリ・プランにRANGESCANが正常に使用されていることが示されます。
Entity Frameworkを使用すると、生成されるSQLにかかる時間が大幅に長くなります(5秒対30ミリ秒)。
Entity Frameworkを使用し、主キーフィールド(NOTE_KEY)でクエリを実行すると、SQLDeveloperの場合と同じように結果が返されます。
私は2つのことを疑っています:
EFおよびOracle.DataAccess-providerが使用可能なnon-unique-indexを使用していないことに問題があります。Entity Framework 5のデバッグシンボルがあれば役に立ちますが、どこにも見つかりません。
パフォーマンスの問題は、クロージャやEFでジェネリックリポジトリパターンを使用する方法に関して、EFのどこかにあります。
リポジトリを次のように呼び出すと、
var notenumber = "1A23456";
var notes = repository.All(n => n.NOTENUMBER == notenumber).ToList();
述語は次のようにメソッドAll
に入ります。
{n => (n.NOTE == value(Tester.Program+<>c__DisplayClass0).notenumber)}
そして、EfProf-profilerは結果のSQLを次のようにトレースします。SELECT "Extent1"."NOTE_KEY" AS "NOTE_KEY",
"Extent1"."NOTENUMBER" AS "NOTENUMBER",
"Extent1"."NOTETEXT" AS "NOTETEXT",
FROM "NOTE_DBA"."NOTE" "Extent1"
WHERE ("Extent1"."NOTENUMBER" = '1PSA0500237500' /* @p__linq__0 */)
また、クエリにかかる時間は約5500ミリ秒です。
一方、リポジトリを次のように呼び出すと
var notes = repository.All(n => n.NOTENUMBER == "1A23456").ToList();
、述語は次のよう
{n => (n.NOTENUMBER == "1A23456")}
になります。EfProf-profilerは、結果のSQLを次のようにトレースします。SELECT "Extent1"."NOTE_KEY" AS "NOTE_KEY",
"Extent1"."NOTENUMBER" AS "NOTENUMBER",
"Extent1"."NOTETEXT" AS "NOTETEXT",
FROM "NOTE_DBA"."NOTE" "Extent1"
WHERE ('1PSA0500237500' = "Extent1"."NOTENUMBER")
また、クエリには約30ミリ秒かかります。
したがって、唯一の違いは、WHERE句の条件の順序と、後者ではEFに置き換えられたパラメーターがないように見えるという事実です。
私はVS2010と.NET4を使用し、EF5(v4.4.0.0)を参照しています。リポジトリのAll-methodは次のとおりです。
public IQueryable<NOTE> All(Expression<Func<NOTE, bool>> predicate = null)
{
var setOfNotes = GetDbSet<NOTE>();
var notesQuery = from note in setOfNotes select note;
if (predicate != null)
{
notesQuery = notesQuery.Where(predicate);
}
return notesQuery;
}
CompiledQueryを作成し、を使用して、.NET4.5setOfNotes.AsNoTracking()
をターゲットにしようとしました。パフォーマンスに違いはありません。
この特定のクエリをすばやく取得する方法の1つは、Oracleの基本的なData Provider for .NET(ODB.NET)を使用して手動でクエリを作成することでしたが、そのソリューションに固執することはしませんでした。繰り返しますが、where句でプライマリフィールドを使用すると、EFと同じAllメソッドを使用してもクエリは高速になります。
したがって、問題はEFのどこかにあるようです。EntityFramework.dllのシンボルだけがあれば、もっと多くのことを知ることができると思います。
EFが述語を呼び出す方法に問題がありますか?'@p_ linq _0'パラメータはEF内でどのように置き換えられますか?