NET Frameworkバージョン4でEntity Framework Code-Firstを使用した非常に単純なクエリに関連する、非常に奇妙なパフォーマンスが見られます。LINQ2Entitiesクエリは次のようになります。
context.MyTables.Where(m => m.SomeStringProp == stringVar);
これには3000ミリ秒以上かかります。生成されたSQLは非常にシンプルに見えます。
SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp],
...
FROM [MyTable] as [Extent1]
WHERE [Extent1].[SomeStringProp] = '1234567890'
このクエリは、Management Studioを実行するとほぼ瞬時に実行されます。 C#コードを変更してSqlQuery関数を使用すると、5〜10ミリ秒で実行されます。
context.MyTables.SqlQuery("SELECT [Extent1].[ID] ... WHERE [Extent1].[SomeStringProp] = @param", stringVar);
したがって、まったく同じSQLの場合、結果のエンティティは両方のケースで変更追跡されますが、両者のパフォーマンスは大きく異なります。何が得られますか?
それを見つけた。 SQLデータ型の問題であることがわかりました。データベースのSomeStringProp
列はvarcharでしたが、EFは.NET文字列型がnvarcharであると想定しています。 DBが比較を行うためのクエリ中に結果として生じる変換プロセスは、長い時間がかかります。 EF教授はここで少し迷っていると思いますが、実行されているクエリのより正確な表現は次のようになります。
SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp],
...
FROM [MyTable] as [Extent1]
WHERE [Extent1].[SomeStringProp] = N'1234567890'
そのため、結果の修正は、正しいSQLデータ型を示すコードファーストモデルに注釈を付けることです。
public class MyTable
{
...
[Column(TypeName="varchar")]
public string SomeStringProp { get; set; }
...
}
EFで作成されたクエリの速度が低下した理由は、nullを許可しないスカラーとnullを許可するスカラーを比較することでした。
long? userId = 10; // nullable scalar
db.Table<Document>().Where(x => x.User.Id == userId).ToList() // or userId.Value
^^^^^^^^^ ^^^^^^
Type: long Type: long?
このクエリには35秒かかりました。しかし、そのような小さなリファクタリング:
long? userId = 10;
long userIdValue = userId.Value; // I've done that only for the presentation pursposes
db.Table<Document>().Where(x => x.User.Id == userIdValue).ToList()
^^^^^^^^^ ^^^^^^^^^^^
Type: long Type: long
素晴らしい結果をもたらします。完了するのにわずか50msかかりました。 EFのバグである可能性があります。
Fluentマッピングを使用している場合、構成の一部としてIsUnicode(false)
を使用して同じ効果を得ることができます-
http://msdn.Microsoft.com/en-us/data/jj591617.aspx#1.9
http://msdn.Microsoft.com/en-us/library/gg696416%28v=vs.103%29.aspx
私は同じ問題を抱えていました(SQLマネージャーから実行するとクエリが高速になります)が、EFから実行するとタイムアウトになります。
エンティティ(ビューから作成された)のエンティティキーが間違っていたことがわかりました。そのため、エンティティには同じキーを持つ行が重複しており、背景でグループ化する必要があったと思います。
私もこの問題を抱えていました。私の場合、犯人はSQL-Server parameter sniffing でした。
私の問題が実際にパラメータスニッフィングに起因する最初の手がかりは、「set arithabort off」または「set arithabort on」でクエリを実行すると、Management Studioで実行時間が大幅に異なることでした。これは、ADO.NETがデフォルトで「set arithabort off」を使用し、Management Studioがデフォルトで「set arithabort on」を使用するためです。クエリプランキャッシュは、このパラメーターに応じて異なるプランを保持します。
クエリのクエリプランのキャッシュを無効にしました。解決策は here です。
また、複雑なefクエリでこれに遭遇しました。 6秒のefクエリを生成したサブ秒のsqlクエリに減らした私にとっての1つの修正は、遅延読み込みをオフにすることでした。
この設定(ef 6)を見つけるには、.edmxファイルに移動し、[プロパティ]-> [コード生成]-> [遅延読み込みが有効]を確認します。 falseに設定します。
パフォーマンスが大幅に向上しました。
次のトリックを使用して、クエリを高速化できます-
ctx.Configuration.ProxyCreationEnabled
_をfalse
に設定します。.Select(c => new {c.someproperty})
は必要なデータのみをフェッチし、全体をフェッチしません。これが役立ったら教えてください。