-1

MySQL .NET コネクタ 6.6.5 を使用して、MySQL データベースに対して C# .NET アプリケーションで Entity Framework 5 を実行しています。

通常、EF が十分に高速でない場合、ストアド プロシージャまたは SQL の直接実行に頼ります。context.Database.SqlQuery ただし、最近、SQL 呼び出しが実際には EF の同等の処理よりもはるかに長い時間がかかるという問題がありました。 ?

(遅い)SQLクエリは次のとおりです。

public sbyte? getFirstRouteTypeFromStop(string primaryCode) {

    string sql = string.Format("SELECT r.route_type FROM stoptimes st INNER JOIN trips t ON st.trip_id = t.trip_id INNER JOIN routes r ON t.route_id = r.route_id WHERE st.stop_id = '{0}' LIMIT 1;", primaryCode);
    return context.Database.SqlQuery<sbyte?>(sql).FirstOrDefault();

}

(高速)EFコードは次のとおりです。

public sbyte? getFirstRouteTypeFromStop(string primaryCode) {

    return context.stoptimes.Where(st => st.stop_id.Equals(primaryCode)).FirstOrDefault().trip.route.route_type;

}

このメソッドはループ内で繰り返し呼び出され、EF の方がはるかに高速です。(少なくとも 1000%) なぜですか?

重要事項:

  • MySQL データベースには、これらすべての列が適切にインデックス化されています。
  • ネイティブ SQL クエリを MySQL で直接実行すると、C# アプリで実行した場合よりもはるかに高速に実行されるように見えます。これは非常に重要な観察結果であると思います。
4

3 に答える 3

2

SqlQuery で INNER JOIN を使用しています。つまり、次のことを意味します。

選択された行の合計 = (停留所の行数) * (ルートの行数) * (トリップの行数)

そして、その巨大なリストで「WHERE st.stop_id = '{0}'」が実行されます...これはSQLクエリの問題だと思います...内部結合は膨大な選択を行い、そこからレコードをフィルタリングします。 ..

一方、EF コードはテーブルの stoptimes でのみフィルター処理します

Where(st => st.stop_id.Equals(primaryCode))

そのため、フィルタリングが高速になり、選択された単一のレコードでルートとトリップが取得されます。

注:- LEFT OUTER JOIN を使用してみてください...クエリが高速になります。

それが役に立てば幸い...

于 2013-10-18T12:15:57.023 に答える
0

すべてまたは一部 (および や などのナビゲーション プロパティ) が既にメモリにある場合がありStoptimesます。この場合、EF はデータベースに 1 回ヒットするだけです (または、少なくともループの反復ごとにヒットするわけではありません)。ループの繰り返しごとにデータベースに移動します。たぶん、ループで何度も繰り返されますか?または、コンテキストを破棄せずに、アプリの以前のコードで取得することはありますか?triprouteSQLQueryprimaryCodeStoptimes

于 2013-10-18T11:22:33.847 に答える