VB6でADOを使ってSQLServerのテーブルを読込む、処理を作りました。
Loop処理中で何度も同じテーブルの違うレコードを同じRecordsetを使って
読み込んでます。1回のループで同じテーブルの違うレコードを4回ほど同じRecordsetで読込みます。
数十回繰り返すと、いままで問題なく読み込んでいたselect文で、応答がなくなり
タイムアウトしてしまいます。
Timeout=30だったのを240に変更したところ、途中で同様に止まりはするのですが
タイムアウトにはならずに、思い出したかのように処理が続行されます。
続行後も、また数十回select文を発行した後に止まってしまい、思い出したかのようにまた続行されます。
タスクマネージャーのパフォーマンスを見ているとクライアント、サーバー共に止まっている間はCPU使用率は0%です。
サーバー、クライアント共にpen4クラスのマシンでメモリも十分に空きはあります。
なにか、ヒントがあればよろしくお願いいたします。
それだけでは、なんともコメントのしようがありません。
せめて、発行しているSQL文を掲載して頂くとか、VBのループ処理部分
の抜粋を掲載して頂くとか・・・
因みにSELECTされたデータの件数は何件程度あるのでしょうか?
またSELECT先のテーブルには何件のデータが登録されているのでしょう
か?
また、SQL Server のバージョンや、サービスパックの適用の有無、
ADOのバージョンも記載して頂ければより細かく調べれますが・・・
※ 通常、Timeoutしてしまう場合、巨大なテーブルに、何万件も
ヒットしてしまうSELECT文の場合、大抵そうなります・・・
そうそう、SQL Serverが稼動しているマシンのOSは?
また、クライアント側マシンのOSは?
以上。
すみません、いろいろ書くと長文になりそうだったもので、なにかヒントでもと思い取り急ぎUPしたもので・・。
クライアント、サーバー共にW2Kです。
SQLSERVERはSQLServer2000です。
ADO2.5Libraryを参照しています。
テーブル件数は2000件程度で、ループ内の各selectの戻り件数は1件です。
読み込む項目は全項目ですが、1レコード512バイト程度です。
KEYに"A0001"と言うようなコードがあり、当然ユニークです。
KEYとは別に親子関係(親子テーブルではなく同じテーブル内でレコード同士の親子関係をもたせています)を示すPARENT_KEYを持たせます。
例えば、"B0001"のPARENT_KEYには"A0001"が設定してあり、"B0001"は"A0001"
の子供となります。
以下のような関係になります。
A0001-B0001-C0001 B0001,B0002はA0001の子、B0003はA0002の子
B0002-C0002 C0001,C0002,C0003はB0001の子
-C0003 C0004はB0002の子
A0002-B0003-C0004
また、A0001,A0002は親が存在しないのでPARENT_KEYには"PARENT"が入っています。
まず、A0001からA0002,B0001,B0002,B0003,C0001...の順にレコードを読み込み、
LOOP処理でまず親をさがします。
親が見つかったら親の弟を捜します。
親がB0001の場合B0002を見つけます。
弟は直近の弟だけです、連番部分が親の連番部分より大きくて最小のものを探します。
PARENT_KEYが"PARENT"になるまで親と親の弟を探します。
C0003を読み込んだ場合はA0001にたどり着くまで検索すると言う処理です。
A0001までたどりついたらC0003の編集(すべての親と親の弟のある項目の最大値
をセット)を行いUPDATEします。
これを最後のレコードまで繰り返します。
実際はHぐらいまで階層が深く、1階層の連番は300ぐらい存在します。
この処理を繰り返しているうちに、以前C0001読み込み時のLOOPでは
B0002のSELECTは問題なく、すぐに返って来ているのに、C0003読み込み時
のLOOPではのB0002のSELECTが返ってこずに、しばらく2分ぐらいすると
いきなり返ってきて、処理が続行されます。続行後もしばらくは順調に読み込んでいるのですがまた突然返ってこなくなり、しばらくするとまた返ってきて続行します。結局最後は正常に終了します。
TIMEOUT=240に設定した場合です。
IsolationLevel = adXactReadUncommittedも設定しました。
SELECT命令(親の検索)
dbCOM.CommandText = "SELECT * FROM FR_INDEX_TBL " _
& " WHERE KEY_ID = '" & WK_PRNT_ID & "'" _
& " AND KEY_NO = ' & WK_PRNT_NO
Set dbRS_TMP = dbCOM.Execute
SELECT命令(親の弟の検索)
dbCOM.CommandText = "SELECT MIN(A.LVL_NO) AS MIN_LVL_NO " _
& " FROM FR_INDEX_TBL A" _
& " WHERE A.KEY_ID = '" & WK_PRNT_ID & "'" _
& " AND A.KEY_NO > " & WK_PRNT_NO
Set dbRS_TMP = dbCOM.Execute
If dbRS_TMP.EOF = False Then
WK_MIN_LVL_NO = dbRS_TMP.Fields("MIN_LVL_NO").Value
'****直近弟を読み込む
dbCOM.CommandText = "SELECT * FROM FR_INDEX_TBL A" _
& " WHERE A.LVL_ID = '" & WK_PRNT_ID$ & "'" _
& " AND A.LVL_NO = " & WK_MIN_LVL_NO
Set dbRS_TMP = dbCOM.Execute
やはり、同じRECORDSETを使いまわししているのがよくないのでしょうか?
う〜ん・・・
アイデア的には、その手法はよいとは思いますが、それを実行させる
にあたって、適したエンジンを使っていないと言うか・・・無茶と、
言うか・・・
階層が深くなるにつれ、たとえ2000レコードでも、1階層深くなる毎
に、×2000回づつループが増えます。
で、A〜Hまでいく・・・最悪のケース
2000×2000×2000×2000×2000×2000×2000回
ループしないと、たどり着けないと思いますが・・・
それはSQLの仕事では無いと思います。またサーバー資源の無駄な
浪費ですので、アルゴリズムを変更されるかテーブル構造を変更し、
インデックス部分でのみのアクセスで終了するような方式に変更され
た方が懸命かと・・・
以上。
ツイート | ![]() |