20

約16,500の都市のテーブルを含むデータベースと、そのデータベースのEFデータモデル(データベースファースト)があります。私はそれらをコードでメモリにプリロードします:

Db.Cities.Load()

...次に、それらを使用するときは、次の各クエリを試しました。

Dim cities() As String = Db.Cities.Select(Function(c) c.CityName).ToArray

Dim cities() As String = Db.Cities.Local.Select(Function(c) c.CityName).ToArray

最初のクエリは高速(〜10ms)ですが、2番目のクエリは最初の実行に約2.3秒かかります(ただし、その後に呼び出されたときの最初のクエリよりも高速です)。

SQL Server Profilerは、最初のクエリが別のマシンのデータベースにヒットしていることを確認しますが、2番目のクエリはそうではないため、これは意味がありません。

をオフDb.Configuration.AutoDetectChangesEnabledにして、ビューを事前に生成してみました。

速くするために何ができ.Localますか?(このアプリケーションを実行しているすべてのクライアントが高速LAN上にあるわけではありません。)

4

3 に答える 3

9

Resharperの便利な機能Localを使用して、プロパティのソースを調べました。上記の 3 行だけを実行している場合、おそらく問題ではない呼び出しが最初に表示されます。しかし、EF は新しい ObservableCollection を作成し、項目ごとに入力します。どちらも、最初の呼び出しでコストがかかる可能性があります。DetectChangesLocal

に対する直接のクエリDbSetは、内部のローカル キャッシュに直接アクセスすると確信している EF データベース プロバイダーにルーティングされます。

于 2012-09-05T07:54:18.000 に答える
6

次の拡張メソッドはIEnumerable<T>、DbSet のローカルにキャッシュされたエンティティを含むを返します。DbSet.Local()コンテキストの変更を検出してObservableCollection<T>オブジェクトを作成するメソッドによって発生する起動オーバーヘッドはありません。

<Extension()>
Public Function QuickLocal(Of T As Class)(ByRef DbCollection As DbSet(Of T)) As IEnumerable(Of T)
    Dim baseType = DbCollection.[GetType]().GetGenericArguments(0)
    Dim internalSet = DbCollection.GetType().GetField("_internalSet", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance).GetValue(DbCollection)
    Dim internalContext = internalSet.GetType().GetProperty("InternalContext").GetValue(internalSet, Nothing)
    Return DirectCast(internalContext.GetType.GetMethod("GetLocalEntities").MakeGenericMethod(baseType).Invoke(internalContext, Nothing), IEnumerable(Of T))
End Function

.QuickLocal19,679 個のエンティティを含む DbSet の呼び出しには 9 ミリ秒.Localかかりますが、最初の呼び出しでは 2121 ミリ秒かかります。

于 2012-09-05T17:50:24.867 に答える
0

最初のクエリから文字列のリストを保存して、代わりにそれを使用してみませんか。

List<string> cities = db.Cities.Select( x=>x.CityName).ToList();

Selectが原因で、ローカルの速度が低下する可能性があります。Selectは、整合性チェックを実行している可能性があります。

于 2012-09-03T05:37:28.677 に答える