SQLが応答しなくなる原因と対処方法

このQ&Aのポイント
  • SQLが応答しなくなっている原因として、CGIが読み込み中のままになっていることが挙げられます。
  • 質問文章では、SQLを約1600回実行した後にページを再読み込みしています。
  • 一部の場合、再読み込みをすると「読み込み中」のままになります。CPU使用率も1%程度になっています。
回答を見る
  • ベストアンサー

SQLが応答しなくなっているのか、CGIが読み込み中のままになってしまいます。

SQLを約1600回実行したら、5秒後にページを再読み込みします。 print "<html><body onload=\"setTimeout('location.reload()',5000)\">"; foreach ... {   ...   # 約1600回繰り返す   @result = select("SQL文");   ... } sub select{   my @result = ();   my($dbh, $sth);   $dbh = DBI->connect('DBI:mysql:データベース:localhost', "ID", "パスワード") or return 0;   $sth = $dbh->prepare("$_[0]");   $sth -> execute() or return 0;   $num_rows = $sth->rows;   $num_of_fields = $sth->{NUM_OF_FIELDS};   $result[0] = $sth->rows;   for ($i=1; $i<=$num_rows; $i++) {     @fetchrow_array = $sth->fetchrow_array;     $result[$i] = join ',', @fetchrow_array   }   $sth -> finish();   $dbh -> disconnect();   return @result; } 最初の1,2回は期待通りに動くのですが、 2,3回ほど再読み込みをすると、「読み込み中」のままになってしまいます。 (期待通りに動く場合、1回の読み込みは20秒程度です。) タスクマネージャを見ると、 期待通りに動いているときは、CPU使用率が60%くらいになっていますが、 「読み込み中」のままの時は1%程度になっています。 SQLサーバーから応答がなくなっているのでしょうか? (簡単なSQLにしてみても同じでした。) 原因がわかる方、よろしくお願いします。 WindowsXP SP2 Apache1.3 ActivePerl5.6 MySQL3.23

  • CGI
  • 回答数3
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

エラーの根本解決にはならないと思いますが、 foreach の外でconnect&disconnectして、select命令に$dbhを引き数として渡すようにしてはいかがでしょう? 用は、DB接続を約1600回から1回に減らすと言う案です。

dennyz_Q
質問者

お礼

>foreach の外でconnect&disconnectして、select命令に$dbhを引き数として渡すようにしてはいかがでしょう? この方法でうまく動きました! $dbh = DBI->connect(...); foreach ... {   ...   # 約1600回繰り返す   @result = select("SQL文", $dbh);   ... } $dbh -> disconnect(); 接続と実行を分けるところまで考えが回っていませんでした。 丁寧なアドバイスありがとうございました。

その他の回答 (2)

回答No.2

Premature end of script headers は、Content-typeを出力する前に何らかの原因で別の文字列が出力されてしまうと出ることがあります。 return 0 する代わりに、 die DBI->errstr なんてしてみると、もうちょっと詳細のエラーメッセージ見れたりしません? セッションはshow processlist で見れますが、今回は接続に失敗しているので、セッションは存在しないと思います。 後、前回の回答に書いた部分は試して頂けましたか?

dennyz_Q
質問者

お礼

>return 0 する代わりに、 die DBI->errstr なんてしてみると、もうちょっと詳細のエラーメッセージ見れたりしません? Apacheのエラーログに以下のように残りました。 [Sat Jun 09 15:11:39 2007] [error] [client 192.168.0.6] DBI connect('データベース:localhost','',...) failed: Can't connect to MySQL server on 'localhost' (10048) at c:\\PROGRA~1\\APACHE~1\\apache\\cgi-bin\\プログラム名.CGI line 68\n [Sat Jun 09 15:11:39 2007] [error] [client 192.168.0.6] Can't connect to MySQL server on 'localhost' (10048) at c:\\PROGRA~1\\APACHE~1\\apache\\cgi-bin\\プログラム名.CGI line 68.\n 10048というエラーがあるので調べてみましたが、 OS(WindowsXP、2003Server)に原因があるのかもしれません。 http://www.mysql.gr.jp/mysqlml/mysql/msg/13216 http://72.14.253.104/search?q=cache:-MRJssTOuB0J:www.hcm-pro.com/choiota/cat13/+MySQL+10048&hl=ja&ct=clnk&cd=5&gl=jp&lr=lang_ja&client=firefox とりあえず、「MySQLからまとめてSELECT→perlで細かく処理」する方法を試してみます。 >後、前回の回答に書いた部分は試して頂けましたか? $sth->rows の箇所は教えていただいたように修正しました。 ありがとうございました。

回答No.1

補足をお願いしたいのですが、 (1) Apacheのエラーログには何も出てないですか? (2) 読み込み中のときのアクセスに対するApacheのアクセスログ は残ってますか? (3) 読み込み中のとき、MySQLにセッションは張られていますか? なお、今回の不具合と関係があるかは定かではないですが、このソースにまずいところがあります。それは$sth->rows です。このメソッドはDELETEやUPDATEでの使用を想定していて、SELECT 文では使用することはお勧めできないとドキュメントにも書いてあります。whileでfetchしても何も返って来なくなるまで回すのが普通のやり方です。 while(@row = $sth->fetchrow_array) { # 処理 }

dennyz_Q
質問者

補足

遅くなって申し訳ありません。わかる範囲で調べてみました。 >(1) Apacheのエラーログには何も出てないですか? [Thu Jun 07 12:06:12 2007] [error] [client 192.168.0.6] Premature end of script headers: c:/program files/apache group/apache/cgi-bin/プログラム名.cgi [Thu Jun 07 12:06:12 2007] [error] [client 192.168.0.6] DBI connect('データベース:localhost','',...) failed: Can't connect to MySQL server on 'localhost' (10048) at c:\\PROGRA~1\\APACHE~1\\apache\\cgi-bin\\プログラム名.CGI line 67\n [Thu Jun 07 12:06:12 2007] [error] [client 192.168.0.6] DBI connect('データベース:localhost','',...) failed: Can't connect to MySQL server on 'localhost' (10048) at c:\\PROGRA~1\\APACHE~1\\apache\\cgi-bin\\プログラム名.CGI line 67\n [Thu Jun 07 12:06:12 2007] [error] [client 192.168.0.6] DBI connect('データベース:localhost','',...) failed: Can't connect to MySQL server on 'localhost' (10048) at c:\\PROGRA~1\\APACHE~1\\apache\\cgi-bin\\プログラム名.CGI line 67\n ...(同じように続く) 67行目はMySQLに接続しようとする場所です。 $dbh = DBI->connect('DBI:mysql:データベース:localhost', "ID", "パスワード") or return 0; "Premature end of script headers" とあるので調べてみたら、 「Content-type: text/html\n\nを出力していない場合が考えられます」とありました。 最初の数行は以下のようなものです。 #!/Perl/bin/perl require './jcode.pl'; require './cgi-lib.pl'; &ReadParse(*in); print "Content-type: text/html\; charset=shift_jis\n\n"; ... また、「パーミッションを755にしたら解決した」という記事もあったのですが、 Windowsであることと、正しく処理できることもあることから、関係ないかと思います。 >(2) 読み込み中のときのアクセスに対するApacheのアクセスログは残ってますか? 192.168.0.6 - - [07/Jun/2007:12:04:52 +0900] "GET /cgi-bin/プログラム名.cgi HTTP/1.1" 200 382 192.168.0.6 - - [07/Jun/2007:12:05:04 +0900] "GET /cgi-bin/プログラム名.cgi HTTP/1.1" 200 382 192.168.0.6 - - [07/Jun/2007:12:06:12 +0900] "GET /cgi-bin/プログラム名.cgi HTTP/1.1" 500 605 1,2行目は期待通りに処理したときのもので、3行目が読み込み中のままになったときのものです。 (読み込み中が続いたので、途中で中止しました。) 500とあるのでサーバーエラーのようです。 >(3) 読み込み中のとき、MySQLにセッションは張られていますか? どのように確認したらよいのかがわかりませんでした。

関連するQ&A

  • Perl初心者です。MySQLから取得したデータをXMLで出力させたいです。

    以下のようにしましたがXMLのエンコードを euc-jp にするときちんと表示されますが、utf-8 にするとダメです。 助言をお願いします。cgiファイルとDB(MySQL)の文字コードはEUC-JP、Perlのバージョンは5.6です。 #!/usr/local/bin/perl use DBI; use Jcode; $sqlStr = "SELECT * FROM Test"; $x = "Content-type: text/xml; charset =utf-8\n\n"; # utf-8 $x .= "<\?xml version=\"1.0\" encoding=\"utf-8\"\?>\n\n"; # utf-8 $x .= "<ROOT>"; $dbh = DBI->connect ("DBI:mysql: AAA: localhost","BBB","CCC "); $sth = $dbh->prepare("$sqlStr"); $sth->execute; $num_rows = $sth->rows; $num_fields = $sth->{NUM_OF_FIELDS}; for ($i=0; $i<$num_rows; $i++) { $x .= "<ROW>"; @a = $sth->fetchrow_array; for ($n=0; $n<$num_fields; $n++) { $a[$n] =~ s/&/&amp;/g; $a[$n] =~ s/</&lt;/g; $a[$n] =~ s/>/&gt;/g; $col = $sth->{NAME}->[$n]; $x .= "<$col>$a[$n]</$col>"; } $x .= "</ROW>"; } $sth->finish; $dbh->disconnect; $x .= "</ROOT>"; Jcode::convert(\$x,'euc','utf8'); # utf-8 print $x; exit;

    • ベストアンサー
    • Perl
  • SQLで別テーブルの参照

    こんにちは。 PostgreSQL+Perl+DBIでCGIを書いています。 テーブルからデータを取得する場合なのですが、table1にはIDのみが登録されていて、table2には、そのIDに対する文字列が登録されているとします。 このような場合に、tableからIDを取得して、そのIDに対するtable2の文字列を一気に取得することは可能でしょうか? つまり、 $dbh=DBI->connect(~); $sth=$dbi->prerare("SELECT id FROM table1 WHERE ~;"); $sth->excecute(); $id=$sth->fetchrow; $sth->finish(); $sth=$dbi->prerare("SELECT str FROM table2 WHERE id=$id;"); $sth->excecute(); $str=$sth->fetchrow; $sth->finish(); $dbh->disconnect(); といった処理をこんな感じに一度に行いたいのです。 $dbh=DBI->connect(~); $sth=$dbi->prerare("~~~~~;"); $sth->excecute(); $str=$sth->fetchrow; $sth->finish(); $dbh->disconnect(); 可能かどうかもわからないのですが、なにか良い方法はありますでしょうか?よろしくお願いします。

  • fetchrow_arrayとfetchrow_hashrefの使い方

    Jやまとです。 PerlからSELECT文を実行して結果の行の値を取得する単純なスクリプトを作成しています。 (1)fetchrow_array使用 (2)fetchrow_hashref使用 以上2通りの方法で試したのですが、(2)がInternal Server Errorになります。 原因が全く分かりません。 分かる方いらしゃいましたら、ご教授願います。 OS:TurboLinux6.2 DB:Oracle8i Apache,PerlはTurboLinux6.2に入っているものをそのまま使用 以下、ソースを記載します。 --------------- (1)fetchrow_arrayを使用して行の値を取得(こっちは動く) $dbh = DBI->connect($ds, $user, $pass) || &dbErr("Database can't connect." . $DBI::errstr); $sql = "SELECT SYSDATE FROM DUAL \n"; $sth = $dbh->prepare( $sql ); $sth->execute or die "Cannot execute. " . $sth->errstr(); $cnt1 =1; while (@row = $sth->fetchrow_array()) { @{$get_date[$cnt1]} = @row; $cnt1++; } --------------- (2)fetchrow_hashrefを使用して行の値を取得(こっちが動かない) $dbh = DBI->connect($ds, $user, $pass) || &dbErr("Database can't connect." . $DBI::errstr); $query = qq{ SELECT SYSDATE FROM DUAL }; $sth = dbh->prepare($query); $sth->execute(); # 実行 if($sth->rows() != 1){ # 該当する行数 # エラー処理 } $rhash = $sth->fetchrow_hashref(); %hash = {%{$rhash}}; $sth->finish(); $get_date = $hash{SYSDATE}; --------------- (2)実行時のerror_log Can't locate object method "prepare" via package "dbh" at /u01/ora1/www/htdocs/hoge.cgi line 30. Premature end of script headers: /u01/ora1/www/htdocs/hoge.cgi --------------- (本文長くてすみません)

    • ベストアンサー
    • Perl
  • Mysqlの接続について

    現在、以下のようなperlのスクリプトを作っているのですが、mysqlへの接続,切断は以下の場合、どちらにした方がいいのでしょうか? (1)の場合 use DBI; $dsn="DBI:mysql:database=dbname:host=localhost"; $dbh=DBI->connect($dsn,'user','pass'); $sth = $dbh->prepare("SELECT no,title,name,date,host From `table1` where no='1'"); $sth->execute; $sth->fetchrow_array; $sth->finish; $sth2 = $dbh->prepare("SELECT no,title,name,date,host From `table2` where no='1'"); $sth2->execute; $sth2->fetchrow_array; $sth2->finish; $dbh->disconnect; (2)の場合 use DBI; $dsn="DBI:mysql:database=dbname:host=localhost"; $dbh=DBI->connect($dsn,'user','pass'); $sth = $dbh->prepare("SELECT no,title,name,date,host From `table1` where no='1'"); $sth->execute; $sth->fetchrow_array; $sth->finish; $dbh->disconnect; $dsn="DBI:mysql:database=dbname:host=localhost"; $dbh=DBI->connect($dsn,'user','pass'); $sth2 = $dbh->prepare("SELECT no,title,name,date,host From `table2` where no='1'"); $sth2->execute; $sth2->fetchrow_array; $sth2->finish; $dbh->disconnect; (1)の場合と(2)の場合の違いは、(1)の場合、最初にデータベースに接続して、一番最後に切断する事で、(2)の場合、毎回データベースへの接続と切断を行う事が違います。 (2)の場合、毎回接続と切断を行うので、2回ほどではあまり変わらないかもしれないのですが、もし10回とか接続と切断を行うとかなり負荷が高くなるような気がするのですが、他のHPなどを拝見すると接続をしたら切断を行うように癖をつけるようにした方がいいと書かれていたりします。 どちらの方が正しいやり方というか、負荷がすくなく使えるのでしょうか?

    • ベストアンサー
    • Perl
  • DBを用いたCGI認証スクリプト(perl、mysql)

    DBに一行一ユーザーの情報があり(メールアドレス 、パスワード)、 IDをメールアドレスとし、 入力したメールアドレスが登録されているか 入力したメールアドレスのパスワードがあっているか、 をチェックするスクリプトです。 初心者のためいろいろのサイトを見ながら作りましたが、下記のソースで何とか動いています。 が、これでよいのか(スマートかどうか)、もっと簡単な方法があるのかどうかをお聞きしたく、質問させていただきました。よろしくお願いいたします。 #!/usr/bin/perl use DBI; use CGI; require "cgi-lib.pl"; #フォームからIDとPWを受け取る &ReadParse(*form); $input_id= "$form{'アイディー'}"; $input_pw= "$form{'パスワード'}"; $TABLE_name = 'メールアドレス'; $form = CGI->new; $ret = eval{ $dbh = DBI->connect('DBI:*******************) }; if ( !$ret ) { print "接続エラーが発生しました\n"; exit(); } else{ print "OK\n"; $sql = "SELECT パスワード FROM $TABLE_name where メールアドレス='$input_id'"; $sth = $dbh->prepare($sql); if(!$sth->execute){ print "SQL実行エラー\n"; exit; } $num_rows = $sth->rows; if($num_rows==0){ print "このEmailは登録されていません。\n"; } else{ #ヒットしたemailの行にあるパスワード=$rec $rec = $sth->fetchrow_array(); #ヒットしたemailの行にある「パスワード=$rec」と入力したパスワードがマッチするかどうか if($rec eq $input_pw){ #認証OK!会員ページへ print "<br>認証OK!<br>"; } else{ #認証NG(Emailは登録されているが、登録したemailとパスワードが一致しない) print "パスワードが違います\n"; } } $sth->finish; $dbh->commit; $dbh->disconnect; }

    • ベストアンサー
    • Perl
  • MySQLとの接続でfetchrow_arrayがwhile文で使えない

    こんばんは、皆さん。 MySQLをPerlから使いたいのですが、 以下のようにやっても、$flagに"OK"が入りませんでした。 つまり、whileは一度もループしないで抜けてしまっているようです。 ------------------------------------------------- use DBI; … sub dbtest{ $dbh = DBI->connect("dbi:mysql:hogeDB:localhost","user","pass"); $sql = "select hoge,fuge from t_name where key='value'"; $sth = $dbh->prepare($sql); $sth->execute; while( ($hoge, $fuge) = $sth->fetchrow_array ){     $flag = "OK"; } $sth->finish; $dbh->disconnect; } ------------------------------------------------- ※実際はユーザ名などは変数にしています。 バージョンは現在、 Perl:v5.8.5 MySQL:5.1.6-alpha となっているようです。 それとちょっと別件ですが、 use autouseの書式は以下でよいのでしょうか? 「use autouse DBI;」 しかし、これだけだとDBIが読み込めてないエラーになるようです。 ご教示よろしくお願いします。

    • ベストアンサー
    • Perl
  • 配列に入った変数を二度使いたい

    perlでDBデータをセレクトし表示させるプログラムで 以下のように一回目のforループでは正常に表示されます。 二度目に表示させようとすると何もデータがなくなっているようです。 print でも、もちろんなにも表示しません。 配列名を変えてもだめでした。とこが原因なのかわかりません。 ステートメントハンドルとかが関係あるのでしょうか? いろいろ調べたのですが、ちょっとわかりませんでした。 申し訳ないのですが、教えてください。 話をまとめるとDBからセレクトした同じ行のデータを2回表示させたいということです。 よろしくお願いします。 my $db = DBI->connect("DBI:Pg:dbname=$UDBNAME",$USERNAME,$USERPASS); my $sth=$db->prepare(" select * from server where no = $no "); $sth->execute; #一回目 for ((my $count)=0; $count<$num_rows;$count++){ my @ar=$sth->fetchrow_array; #二回目 for ((my $count)=0; $count<$num_rows;$count++){ my @ar=$sth->fetchrow_array;

    • ベストアンサー
    • Perl
  • データベースから取得したデータを配列に格納

    データベースから取得したデータを配列に格納することができません。 唯一、以下の方法で格納できたのですが、この場合データベースの項目の数が、あらかじめ分かっている場合にしか使用できません。googleで検索して出てくるサンプルは全てループ内でprintしているので参考になりませんでした。 やりたいことは単純で、データベースにクエリーを発行した結果の複数レコードをそのまま配列に格納することです。perlに詳しい方がおられましたらよろしくお願いします。 _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ■データベース内のデータ id=1,subid=1,data1=aaa id=1,subid=2,data1=bbb id=1,subid=3,data1=ccc ■期待する結果 @result = ("1","1","aaa", "1","2","bbb", "1","3","ccc", ) _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ ■実際のソース ********************************************************** use DBI; #//■DB接続 $db = DBI->connect("DBI:mysql:$DbName:$DbHost", $DbUser, $DbPass); $sth = $db->prepare($sql); $sth->execute; $cnt = $sth->rows; for($i=0; $i<$cnt; $i++){ @work = $sth->fetchrow_array; @result[$i] = ([$work[0],$work[1],$work[2],]); } #//■CLOSE $sth->finish; $db->disconnect; for($i=0; $i<$cnt; $i++){ print "<p>".$result[$i][0]."/".$result[$i][1]."/".$result[$i][2]."</p>\n"; } **********************************************************

    • ベストアンサー
    • Perl
  • perlを使ってレコード件数を取り出してみると、すごい数が・・・。

    perlのDBIモジュールを使って、mysqlのレコード件数を表示させてみると、すごい数が表示されました。ソースは以下の通りです。 use DBI; $dbh=DBI->connect("DBI:mysql:データベース名:サーバ名", "ユーザ名", "パスワード") || die $DBI::errstr; if(!$dbh){ print "エラーです。入力を確認してください。"; exit; }else{ #接続成功 # SELECT文発行 $sth=$dbh->prepare("SELECT sei, mei, mail FROM table"); #実行 $sth->execute; $num_rows = $sth->rows; print "該当 $num_rows, 件\n"; # 開放 $sth->finish; # AUTO COMMITがOFFの場合はCOMMITが必要 $dbh->commit; # 切断 $dbh->disconnect; } 実行すると該当 4294967294, 件 とブラウザに表示されました。僕はレンタルサーバを使っているわけですが、僕のデータベースにはレコードは3件しかないのです。これはレンタルサーバのデータベースすべての件数が表示されているのでしょうか? なんだかSQLを実行するのが怖いので、考えられる原因を教えてください。よろしくお願いします。 プログラムを初めてまだ、数ヶ月しか経ってない初心者なので、みなさんの知恵を貸していただけると幸いです。

    • ベストアンサー
    • MySQL
  • ハッシュのキー追加について

    とある既存プログラムに機能追加したいのですが上手くいきません。 ハッシュだとは思うのですが、%だったり$だったりしてよくわからなくなってしまいました。 どこがおかしいか教えていただけないでしょうか。 <概要> もともとあった(1)と(3)の処理の間に、(2)を行う <ソース> (1)DBから1レコードを取得する $sql = "select * from tenpo where id=5;"; $sth = $dbh->prepare($sql); $sth->execute(); $shop = $sth->fetchrow_hashref(); (2)別TABLEから値を取得し、(1)に追加する $sql = "select todoufuken from area where id=5;"; $sth = $dbh->prepare($sql); $sth->execute(); @todoufuken= $sth->fetchrow_array; $shop{place} = $todoufuken[0]; (3)$shopの情報をサブルーチンに渡す ソース略

    • ベストアンサー
    • Perl

専門家に質問してみよう