0

私のプログラムでは、MySQL データベースからデータをコピーしています。理論的には、ページングによって結果セットを削減しています。各セルに非常に大きなデータがなく、約 25 列のデータがある 30 行のデータには、まだ 600 ~ 800 ミリ秒の長い時間がかかるようです。

これは、データベースにアクセスしてデータを取得するために耐えなければならないパフォーマンス ヒットですか? このデータを頻繁に更新していますが、ユーザーごとに異なるデータセットであるため、メモリにキャッシュしたりプリロードしたりすることはできません。

ここからどのように進むかについて、いくつかの提案が欲しいです。ページネーションの合計行カウントを行うために別のストアド プロシージャを作成することを検討しましたが、主なヒットは、データをプログラムにコピーしてリストにコピーし、Web ページ ビューの JSON を生成する必要がある場合のようです。

私はこれが初めてで、これらの結果を生成するのに時間がかかるため、フロントエンドページの応答性が低下し始めていると思います. ページの更新に 1.8 ~ 2.5 秒かかるのは、30 件の結果を表示するグリッドを再読み込みするには長すぎるようです。

前もって感謝します。

編集:追加の詳細:

テーブル内のすべての主キーにインデックスが付けられます。はい、最も時間がかかる EF クエリをプロファイリングしました。ページ選択以外のことは何もしていないようです。元

sql = "System.Collections.Generic.List`1[PeerTrader.usercollectionenhancedview].OrderBy(Param_0 => Param_0.CardName).Skip(90).Take(30)"

私はコントローラーの診断を測定しており、基本的にクライアント側はディスプレイの表示に実際のオーバーヘッドを追加していないため、クライアント側を取り除くことができます。基本的に、JSON データを準備してクライアントに返すのにかかる時間は同じです。

結果の合計カウントが約 20K になるストアド プロシージャからは、一般に 30 ページになります (行数を 5 に減らしても所要時間は実際には変わりません)。

本当のヒットは、データベースから実際にデータを「読み取る」時点にあります。そのため、データベースから実際に結果をロードする部分を挿入すると、最大のヒットとなるように見えます。サーバーがMySQLサーバーで行うページ呼び出しをエミュレートする必要があるページクエリを実行すると、60ミリ秒のオーダーで結果が返されます。

これが私のコントローラーアクションです: 以下の例では、フィルターの後にデータセット全体をリストにコピーしています。これは、5、30、または 20K 相当の行でコピーする天候は関係ないように思われるためです。読み取り操作で同じヒットが発生すると、後でコントローラーでデータセットを何度も列挙できます。

public ActionResult GridData(string sidx, string sord, int page, int rows, bool _search, string filters)
    {
    ///**********Diagnostics Start********
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();
    ///**********Diagnostics End********

    MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
    int currentUserID = (int)currentUser.ProviderUserKey;

    var serializer = new JavaScriptSerializer();
    //Filters f = (!_search || string.IsNullOrEmpty(filters)) ? null : serializer.Deserialize<Filters>(filters);
    Filters_IQueryable f = (!_search || string.IsNullOrEmpty(filters)) ? null : serializer.Deserialize<Filters_IQueryable>(filters);

    IQueryable<usercollectionenhancedview> query = db.SingleUserCollectionView(currentUserID).AsQueryable();


    var filteredQuery = (f == null ? query : f.FilterObjectSet(query)).ToList();

    ///**********Diagnostics Start********
    sw.Stop(); long t1 = sw.ElapsedMilliseconds; sw.Start();
    System.Diagnostics.Debug.WriteLine("");
    System.Diagnostics.Debug.WriteLine("**************");
    System.Diagnostics.Debug.WriteLine("T1: " + t1);
    ///**********Diagnostics End********

    int totalRecords;

    totalRecords = filteredQuery.Where(x => x.fk_IdUsers == currentUserID).Count();
    pagedQuery = filteredQuery.AsQueryable().Where(x => x.fk_IdUsers == currentUserID).OrderBy(sidx + " " + sord).Skip((page - 1) * rows).Take(rows);

     ///**********Diagnostics Start********
     sw.Stop(); long t2 = sw.ElapsedMilliseconds; sw.Start();
     System.Diagnostics.Debug.WriteLine("T2: " + t2);
     ///**********Diagnostics End********

お知らせいただけない場合でも、さらにコメントできるように十分な追加情報を追加したことを願っています。私の問題を調査していただきありがとうございます。

編集2:

sql = "System.Data.Objects.ObjectResult1[PeerTrader.usercollectionenhancedview].OrderBy(Param_0 => Param_0.CardName).Skip(0).Take(30)" When I go looking on my DB, the actual call on the DB to do theorder by` は実際にはかなりの時間がかかり、実際のデータベース自体で 300 ミリ秒かかります。高価なステップダウンを追跡したように

4

1 に答える 1

0
var filteredQuery = (f == null ? query : f.FilterObjectSet(query)).ToList();

上記の行は疑わしいようです。ここを参照してください:

ToList(IEnumerable) メソッドは、即時のクエリ評価を強制します

カウントと 30 個のアイテムだけが必要な場合は、何千もの結果を具体化する必要はありません。以下のクエリは、実体化されたコレクションではなく、データベースで動作するように書き直す必要があります。count() と Skip().Take() を使用して生成された SQL は、結果を必要なものだけに制限するのに十分なはずですが、使用して実際のクエリを確認することをお勧めします。ObjectQuery.ToTraceString()

totalRecords = filteredQuery.Where(x => x.fk_IdUsers == currentUserID).Count();
pagedQuery = filteredQuery.AsQueryable().Where(x => x.fk_IdUsers == currentUserID)
                          .OrderBy(sidx + " " + sord).Skip((page - 1) * rows).Take(rows);

.AsNoTracking()それでも問題が発生し、それが読み取り専用の状況である場合は、プロキシ生成を使用してオフにすることができます。

于 2013-02-02T21:19:13.907 に答える