none
DataGridViewの表示時間が長い時の対策について(初回アクセス時) RRS feed

  • 質問

  • 使用サーバー:Windows Server 2003 R2
    VB2010 Express
    使用PC:Windows 7 Ultimate

    上記の環境でサーバーに接続し、VBでプログラムを書いています。

    複数のテーブル(6個)からデータを集めて、DataTableを作成します。
    このうちの一つのテーブルは、データ数が約120万件あります。
    しかも、これは2回必要です。他のテーブルも、データ数は数万から10数万件です。
    ということで、Datatableは、結果として7個になります。

    この複数のテーブルから、1個のDatatableを作ります(顧客ID=Client_IDは、指定条件)。
    合成Datatableは、出来ています。 これをDatasourceとしてDataGridViewを表示させます。

    データ数のヒットが多い時は、DataGridview表示までに初回は時間がかかるので、Datatable作成所要時間を調べました。
    顧客IDをA,Bとします。Aは、検索ヒット数4,159件。 Bの該当データ数は、4件です。

    初回Datatable作成時間
    A:23秒~30秒
    B:0.9秒

    2回目以降のDatatable作成時間
    A:0.3秒!!
    B:0.06秒

    データ数のヒットが多い時は、DataGridview表示までに、初回は時間がかかるようです。
    しかし、2回目以降の表示は、初回表示が30数秒かかっていても、1秒強(1.5秒くらい)で表示します。

    この原因は、クライアント側(そして、プログラム)に問題があるのでなく、サーバーの能力に問題があるようです。
    初回接続時は、サーバーがルート(?)を作ったり必要なバッファを準備したりで、時間がかかっているのだそうです。
    一回これを実行すると、サーバーは経路(?)やバッファ(メモリ)をそれ専用として保存しておくので、2回目以降は速くなります。

    初回30数秒は我慢できないですが、2回目の1.5秒くらいなら我慢できます。 
    これは、他のクライアントPCが、そのデータ(120万~300万件)にアクセスしても適用されます。
    つまり、他のクライアントは初回でも1.5秒で表示します。

    で、実験として、サーバーの電源を落とし再度入れます(再起動でも良い?)。
    すると、A,Bとも再度初回扱いとなり、Aの表示は23~26秒かかります。2回目は、1.5秒!
    要するに、初回アクセス時のサーバーの能力の問題のようです。
    初回サーバーアクセス時の所要時間が長い場合の対策が必要です。


    この対策として;
    1.datatableの行数(.rows.count)を数えてのコメント表示は、無意味。
      理由は、datatable作成自体に時間がかかるのだから。

    2.表示完成までに、例の”帯表示”を考えましたが、
      ①この表示自体が時間を食い、データ数が少ない時は返って邪魔。
      ②また、datatable作成自体に時間がかかっている、ということは、サーバーがクライアントにデータを投げる(配達する)のに
       時間かかっているのだから、この帯表示も無意味? 帯表示が始まるまでに時間かかるだけとしたら、無意味です。

    3.コマンドボタンを押したときに検索が始まるのだから、ボタンを押したときにコメント表示する。
      (コメント:”表示までに時間がかかる場合があります。”---とか、。)

    4.上記の3は、非常手段ですが、このコメント自体がうるさい、とか作業の邪魔(時間を取られる)とかの意見がでてくる可能性があります。
      該当データ数が多い時は必要ですが、通常の場合はうるさいだけ、と思われます。

    で、ある方法を考えました。
    このコマンドボタンを押した瞬間に、砂時計マークを表示し、DataGridView表示寸前に、このマークを消せば良いのでは? 、と。

    この方法をご存じの方、ぜひ教えていただけますか。
    (サーバー、ハードの性能を向上させるのも一つの方法ですが、ここでは別問題ですので。)

    通常表示されている帯表示についの私の理解が間違っているのかもしれません。問題は、上記2の②ですね。

    よろしく、お願いします。

    YKsaila


    • 編集済み yksaila 2013年1月17日 3:31
    2013年1月17日 3:27

回答

  • yksaila さま よろしく。
     
    マウスの表示を変えるのなら
    待機状態
      Me.Cursor = Cursors.WaitCursor
    標準
      Me.Cursor = Cursors.Default

     (Cursor もしくは マウス でヘルプを検索すれば出て来ると思いますが ... )
     
    これでよろしいのでしょうか?

    しかし、根本的に別の問題がありそうな気がしますが、今は頭が回らないので勘弁ください。

    • 編集済み ShiroYuki_Mot 2013年1月17日 6:32 改行など変更
    • 回答の候補に設定 佐伯玲 2013年1月21日 6:59
    • 回答としてマーク yksaila 2013年1月24日 8:26
    2013年1月17日 6:24
  • 通常表示されている帯表示についの私の理解が間違っているのかもしれません。問題は、上記2の②ですね。

    2回目で劇的に速くなり、1.5秒しかかかっていませんから、明らかにサーバーにおけるデータの読み出し時間が大きなウエイトを占めています。
    SQL Serverにおいてインデックスを作成されていますか? 作成してあれば、少なくとも取得する件数のみを知る場合は、速度の向上が見込めると思います。その件数を母数として、帯表示(ProgressBarのことですよね?)することは可能です。心配されているような表示時間による遅延はわずかだと思います。
    取得するデータテーブルが6つあるわけですから、母数を件数ではなく6とし、1つのデータテーブルを作成する度にProgressBarを1つずつ増やしても良いかもしれません。2回目以降は1.5秒しかかかっていませんから、ProgressBarが全て伸びきってからDataGridViewに表示されるまでの時間はわずかだと思います。

    参考までに、サーバー側での処理の時間などは、SET STATISTICS IO ONなどで見られると良いと思います。初回時間がかかるのは、推測されている通り、デスクからの読み出しやバッファなどが影響していると思われます。

    (参考)
    SQL Azureパフォーマンス改善手段
    http://sqlazure.jp/b/sqlazure/260/

    バッファの影響がどの程度なのかは、DBCC DROPCLEANBUFFERSでバッファをクリアすると確かめられると思います。

    (参考)
    DBCC DROPCLEANBUFFERS (Transact-SQL)
    http://msdn.microsoft.com/ja-jp/library/ms187762(v=sql.105).aspx

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答の候補に設定 佐伯玲 2013年1月21日 6:59
    • 回答としてマーク yksaila 2013年1月24日 21:47
    2013年1月18日 4:43
    モデレータ
  • 1.テーブルが6個は、私の誤解でした。詳細は省きますが、同僚からの私への伝達ミスでした。
     一個のテーブルで済みました。 でも、データ件数は、約112万件です!

    2.実は、もう少し(?)多いものがありました。検索表示件数が、約8200件。

    3.サーバーの電源を切るか再起動して、初期状態に戻して実験した結果を記します:()内は検索ヒット数、母体は112万件。
      他のデータにアクセスせず、検索もせず、再起動後の初めてのアクセスです(A,B,C ともに、初アクセス)。
         
               初回      二回目     三回目    4回目以降  
      A(8230件)   ×      ×       17~20秒     1.5秒
      B(4150件)  17~20秒       1.5秒         1.5秒            1.5秒
      C(4件)         0秒(一瞬)      0秒           0秒              0秒


    サーバーの設定を変更してタイムアウトまでの時間を延長することも考えましたが(方法は、いまのところ知りません)、
    そうすると、他への悪影響もあるかな、とも思い目下のところ、これは延期です。それに、現実的でないです。

    問題は、Aですが、エラーコメントを出し、かつご教示頂いたマウスカーソルの砂時計マークの表示で対処することにします。
    砂時計マークの表示は便利ですね。助かりました(今まで、知りませんでした)!

    通常は、サーバーの電源は入れっぱなしですし、初使用時(例:再起動時)にAに当たる確率も、きわめて低いものです。
    再起動時に、初めてBにあたってから、Aにいくとタイムアウトにはなりません。
    B表示に、18秒。次に、A表示で同じく18秒(タイムアウトには、なりません。 サーバーが学習するようです)。
    もちろん、二回目以降は、A・Bともに、表示まで1.5秒です。


     
    4.コードも少し改善して、速くなるようにしたつもりです。
      また、サーバーからデータを引き出すとき、日付検索は時間がかかるようなので(Time Outになります)、
      日付検索がある場合は、一旦、datatableに移してから、ここから日付検索して別のdatatableを作成しました。
         
          dt = ds.Tables(0)  ’サーバーから引き出したDataTable

                'datatable(dt)からデータ検索(日付条件指定)して、新たにdatatable作成--dt_Span。これをDataGridViewのDatasourceとする。
                Dim dt_Span As New DataTable  'DataGridView1のデータテーブル(DataSource)とする。
                dt_Span = dt.Clone  'データ構造コピー(Clone)
                Dim span1, span2 As Date
                span1 = CDate(Me.TX_TmSpan1.Text)
                span2 = CDate(Me.TX_TmSpan2.Text)
                For Each DataRow In dt.Select("TradeDate >= '" & span1 & "' and TradeDate <= '" & span2 & "'")
                    dt_Span.ImportRow(DataRow)
                Next DataRow

                 '▼DataGridView1の値の表示---DataGridView1の内容表示
                Me.DataGridView1.DataSource = dt_Span

       この方法は、うまくいっています。 期間検索があるときは、圧倒的に速くなりました。

    5.SQL サーバーのindexの件は、これから確認します(私が作成したものでなく、もとからあるものなのです)。

    もっと、勉強しなくてはいけませんね。

    有難うございました。

    YKsaila










    • 回答としてマーク yksaila 2013年1月24日 8:30
    • 回答としてマークされていない yksaila 2013年1月24日 8:48
    • 回答としてマーク yksaila 2013年1月24日 8:48
    • 編集済み yksaila 2013年1月24日 8:52
    2013年1月24日 8:29
  • 事後報告します(ここを、訪問される方で、私と同じく初心者の方のために、です)。

    知人(ネットワーク構築の専門家)に、サーバーを入れ替えてもらいました(サーバー用PCを新規交換)。
    そろそろ、交換すべき時期なのだそうです。

    新PCは、同じWin Server 2003 R2ですが、SQL2005(以前は、SQL2000)にしました。
    今までのサーバーは、実験用・学習用だったようで、サーバーの容量・能力が小さかったようです。 これで実用上、間に合うことも多いということでしたが、先を考えてのことです。

    で、新規サーバーでの上記実験結果を報告します。

    データA:サーバーの電源を入れてから初アクセス(他のデータにアクセスせずに)での表示時間を再調査。

    Aは、新サーバーでは、タイムアウト無し(以前は2回)、初回 9.5秒、二回目以降は 1~1.5秒です。
    他のデータへのアクセス後でのAの初アクセスでは、二回目以降と大体同じで、短いです。
    データAは特殊例ですので、普通のデータでは、初アクセスでも 1~2秒以内です。


    1.INDEXは、指定済みでした(Client_IDにです)。
    2.検索を速くするには、もっと高度な技術もあるそうですが、現段階では、これで良さそうです。

    ここで学んだこと:
    表示時間が長いのは、サーバーの能力にも依存すること。また、タイムアウト(エラー)になるときでも
    1、2回試行すればうまくいくこと(バッファ・メモリーの準備がされること、次回アクセスで生かされ、その後は普通になる)。
    再起動すればサーバーは初期状態に戻るので、表示時間は初アクセスでの表示時間となること。

    ただ、サーバーの能力が低いことには利点もありました(私の学習にとって、です)。
    コード上での少しの欠陥でも症状がでますので、原因を調べたりしてコード改善の努力のきっかけになりました。

    ところが、サーバーの能力が高いと、この努力をしなくなる可能性があるので、十分に自戒しないといけないと、自分に言い聞かせています。

    以上です。

    YKsaila

    • 回答としてマーク yksaila 2013年2月11日 10:34
    2013年2月11日 10:31

すべての返信

  • yksaila さま よろしく。
     
    マウスの表示を変えるのなら
    待機状態
      Me.Cursor = Cursors.WaitCursor
    標準
      Me.Cursor = Cursors.Default

     (Cursor もしくは マウス でヘルプを検索すれば出て来ると思いますが ... )
     
    これでよろしいのでしょうか?

    しかし、根本的に別の問題がありそうな気がしますが、今は頭が回らないので勘弁ください。

    • 編集済み ShiroYuki_Mot 2013年1月17日 6:32 改行など変更
    • 回答の候補に設定 佐伯玲 2013年1月21日 6:59
    • 回答としてマーク yksaila 2013年1月24日 8:26
    2013年1月17日 6:24
  •  設計が行えていないように思えます。まずは、設計を行うべきでしょう。

     「しかも、これは2回必要です」ということですが、この文章からは2回行う必要性がわかりません。もっとも、質問の主題とは関係なく、質問にいたった理由なので、今回は省きます。

     「サーバーは経路(?)やバッファ(メモリ)をそれ専用として保存しておくので」という文からは、ネットワーク上のことのように思えます。しかし、そうではないはずです。ファースト サーチの時間を短くする方法はいくつかあります。最適なのは、適切なインデックスを作り、インデックスを使用して検索することです。

     通常、マルチ スレッドにすることを検討します。BackGroundWorker クラスですね。ただ、これを使うなら、設計を十分に行っておかなければなりません。

     「で、ある方法を考えました。」はい、いいことです。しかし、そこでとまらないでください。「果たして、本当にそれでいいだろうか。こんな場合はどうだろう?あんな場合はどうだろう?」と検証してください。

     本当に、あなた自身が作らなければならないのですか?身の丈を超えるものを作ろうとしているように思います。いえ、あなたが勉強することを否定するわけではありません。しかし、足し算を知らない人に掛け算を教えても、丸暗記はできますが、どのような場面でどのように使うのかはわかりません。そのように、プログラミングにも階段を上るように積み上げていくものがあります。それを飛ばしているように思います。

     まず、「伝えたいことを伝えきれる」ようになることを目指してください。プログラミングは、自分がして欲しい事をコンピュータがわかる言葉で書くことです。つまり、伝えたいことを十分に表現できなければなりません。人間は、さまざまに想像します。しかし、コンピュータは言われた事しかできません。伝えたいことを、コンピュータにもわかるように表現できなければ、コンピュータは行ってくれないのです。

     過去に、「日本語で、やりたいことを書き出して出してください。それを実現する方法を書き出してください。」と書いたと思います。「プログラミングをする」というのは、(日本人なら)日本語を VB なり C# という言語に翻訳していくことです。元の日本語ができていないなら、プログラムが意図したとおりに動くことは、決してありません。


    Jitta@わんくま同盟

    • 回答の候補に設定 佐伯玲 2013年1月21日 6:59
    • 回答の候補の設定解除 yksaila 2013年1月24日 21:46
    2013年1月18日 1:29
  • 通常表示されている帯表示についの私の理解が間違っているのかもしれません。問題は、上記2の②ですね。

    2回目で劇的に速くなり、1.5秒しかかかっていませんから、明らかにサーバーにおけるデータの読み出し時間が大きなウエイトを占めています。
    SQL Serverにおいてインデックスを作成されていますか? 作成してあれば、少なくとも取得する件数のみを知る場合は、速度の向上が見込めると思います。その件数を母数として、帯表示(ProgressBarのことですよね?)することは可能です。心配されているような表示時間による遅延はわずかだと思います。
    取得するデータテーブルが6つあるわけですから、母数を件数ではなく6とし、1つのデータテーブルを作成する度にProgressBarを1つずつ増やしても良いかもしれません。2回目以降は1.5秒しかかかっていませんから、ProgressBarが全て伸びきってからDataGridViewに表示されるまでの時間はわずかだと思います。

    参考までに、サーバー側での処理の時間などは、SET STATISTICS IO ONなどで見られると良いと思います。初回時間がかかるのは、推測されている通り、デスクからの読み出しやバッファなどが影響していると思われます。

    (参考)
    SQL Azureパフォーマンス改善手段
    http://sqlazure.jp/b/sqlazure/260/

    バッファの影響がどの程度なのかは、DBCC DROPCLEANBUFFERSでバッファをクリアすると確かめられると思います。

    (参考)
    DBCC DROPCLEANBUFFERS (Transact-SQL)
    http://msdn.microsoft.com/ja-jp/library/ms187762(v=sql.105).aspx

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    • 回答の候補に設定 佐伯玲 2013年1月21日 6:59
    • 回答としてマーク yksaila 2013年1月24日 21:47
    2013年1月18日 4:43
    モデレータ
  • こんにちは、yksaila さん
    フォーラムオペレータの佐伯 玲 です。

    その後の状況はいかがでしょうか?
    みなさんから情報が寄せられておりますのでご確認いただき状況をご返信いただけましたらと思います。

    宜しくお願い致します。
    __________________________
    日本マイクロソフト株式会社 フォーラム オペレータ 佐伯 玲

    2013年1月24日 0:50
  • 佐伯様へ

    有難うございます。 そして、ご迷惑をおかけしました。

    あれから、いろいろと実験していました。 このフォーラムを読んでしまうと、自分の方向が制限されてしまう気がしていましたので、まずは独力で、各種確認・実験を続けていました。

    今日/明日中に、まとめ(または、質問)を書きます。

    YKsaila

    2013年1月24日 7:37
  • 1.テーブルが6個は、私の誤解でした。詳細は省きますが、同僚からの私への伝達ミスでした。
     一個のテーブルで済みました。 でも、データ件数は、約112万件です!

    2.実は、もう少し(?)多いものがありました。検索表示件数が、約8200件。

    3.サーバーの電源を切るか再起動して、初期状態に戻して実験した結果を記します:()内は検索ヒット数、母体は112万件。
      他のデータにアクセスせず、検索もせず、再起動後の初めてのアクセスです(A,B,C ともに、初アクセス)。
         
               初回      二回目     三回目    4回目以降  
      A(8230件)   ×      ×       17~20秒     1.5秒
      B(4150件)  17~20秒       1.5秒         1.5秒            1.5秒
      C(4件)         0秒(一瞬)      0秒           0秒              0秒


    サーバーの設定を変更してタイムアウトまでの時間を延長することも考えましたが(方法は、いまのところ知りません)、
    そうすると、他への悪影響もあるかな、とも思い目下のところ、これは延期です。それに、現実的でないです。

    問題は、Aですが、エラーコメントを出し、かつご教示頂いたマウスカーソルの砂時計マークの表示で対処することにします。
    砂時計マークの表示は便利ですね。助かりました(今まで、知りませんでした)!

    通常は、サーバーの電源は入れっぱなしですし、初使用時(例:再起動時)にAに当たる確率も、きわめて低いものです。
    再起動時に、初めてBにあたってから、Aにいくとタイムアウトにはなりません。
    B表示に、18秒。次に、A表示で同じく18秒(タイムアウトには、なりません。 サーバーが学習するようです)。
    もちろん、二回目以降は、A・Bともに、表示まで1.5秒です。


     
    4.コードも少し改善して、速くなるようにしたつもりです。
      また、サーバーからデータを引き出すとき、日付検索は時間がかかるようなので(Time Outになります)、
      日付検索がある場合は、一旦、datatableに移してから、ここから日付検索して別のdatatableを作成しました。
         
          dt = ds.Tables(0)  ’サーバーから引き出したDataTable

                'datatable(dt)からデータ検索(日付条件指定)して、新たにdatatable作成--dt_Span。これをDataGridViewのDatasourceとする。
                Dim dt_Span As New DataTable  'DataGridView1のデータテーブル(DataSource)とする。
                dt_Span = dt.Clone  'データ構造コピー(Clone)
                Dim span1, span2 As Date
                span1 = CDate(Me.TX_TmSpan1.Text)
                span2 = CDate(Me.TX_TmSpan2.Text)
                For Each DataRow In dt.Select("TradeDate >= '" & span1 & "' and TradeDate <= '" & span2 & "'")
                    dt_Span.ImportRow(DataRow)
                Next DataRow

                 '▼DataGridView1の値の表示---DataGridView1の内容表示
                Me.DataGridView1.DataSource = dt_Span

       この方法は、うまくいっています。 期間検索があるときは、圧倒的に速くなりました。

    5.SQL サーバーのindexの件は、これから確認します(私が作成したものでなく、もとからあるものなのです)。

    もっと、勉強しなくてはいけませんね。

    有難うございました。

    YKsaila










    • 回答としてマーク yksaila 2013年1月24日 8:30
    • 回答としてマークされていない yksaila 2013年1月24日 8:48
    • 回答としてマーク yksaila 2013年1月24日 8:48
    • 編集済み yksaila 2013年1月24日 8:52
    2013年1月24日 8:29
  • ShiroYuki_Motさんへ

    有難うございました。

    以下で、うまくいきました。

    >マウスの表示を変えるのなら
    >待機状態
    >  Me.Cursor = Cursors.WaitCursor
    >標準
    >  Me.Cursor = Cursors.Default

    YKsaila

    2013年1月24日 8:46
  • 事後報告します(ここを、訪問される方で、私と同じく初心者の方のために、です)。

    知人(ネットワーク構築の専門家)に、サーバーを入れ替えてもらいました(サーバー用PCを新規交換)。
    そろそろ、交換すべき時期なのだそうです。

    新PCは、同じWin Server 2003 R2ですが、SQL2005(以前は、SQL2000)にしました。
    今までのサーバーは、実験用・学習用だったようで、サーバーの容量・能力が小さかったようです。 これで実用上、間に合うことも多いということでしたが、先を考えてのことです。

    で、新規サーバーでの上記実験結果を報告します。

    データA:サーバーの電源を入れてから初アクセス(他のデータにアクセスせずに)での表示時間を再調査。

    Aは、新サーバーでは、タイムアウト無し(以前は2回)、初回 9.5秒、二回目以降は 1~1.5秒です。
    他のデータへのアクセス後でのAの初アクセスでは、二回目以降と大体同じで、短いです。
    データAは特殊例ですので、普通のデータでは、初アクセスでも 1~2秒以内です。


    1.INDEXは、指定済みでした(Client_IDにです)。
    2.検索を速くするには、もっと高度な技術もあるそうですが、現段階では、これで良さそうです。

    ここで学んだこと:
    表示時間が長いのは、サーバーの能力にも依存すること。また、タイムアウト(エラー)になるときでも
    1、2回試行すればうまくいくこと(バッファ・メモリーの準備がされること、次回アクセスで生かされ、その後は普通になる)。
    再起動すればサーバーは初期状態に戻るので、表示時間は初アクセスでの表示時間となること。

    ただ、サーバーの能力が低いことには利点もありました(私の学習にとって、です)。
    コード上での少しの欠陥でも症状がでますので、原因を調べたりしてコード改善の努力のきっかけになりました。

    ところが、サーバーの能力が高いと、この努力をしなくなる可能性があるので、十分に自戒しないといけないと、自分に言い聞かせています。

    以上です。

    YKsaila

    • 回答としてマーク yksaila 2013年2月11日 10:34
    2013年2月11日 10:31