3

Oracle 8 に接続する DBI モジュール (バージョン 1.601) を使用する Perl スクリプトに問題があります。OS は FreeBSD 7.0 です。

スクリプトは接続を開き、一度に 1 行/1 行ずつデータを挿入して CSV ファイルをループし、接続を閉じて終了します。cron ジョブは、このスクリプトを 30 分ごとに実行し、着信 CSV ファイルを処理します。場合によっては、スクリプトが途中で処理を停止し (新しいデータが挿入されず、それ以上 CPU 時間を消費しない)、強制終了する必要が生じることがあります。

CSV ファイルにはサイズのしきい値があるようです。35000 行未満の場合、スクリプトは実行され、問題なく終了します。そうしないと、プロセスが停止し、プロセスが (一見) 休止状態/待機状態になります。

SQL*Plus を介してのみ Oracle8 にリモート アクセスできます。Oracle v$session テーブルを確認し、これらの停止したプロセスの接続が閉じられていないことを確認したため、リソース制限に達したのではないでしょうか? FreeBSD で「limits」を実行すると、次の結果が得られます。

cputime          infinity secs
filesize         infinity kB
datasize           524288 kB
stacksize           65536 kB
coredumpsize     infinity kB
memoryuse        infinity kB
memorylocked     infinity kB
maxprocesses         5547
openfiles           11095
sbsize           infinity bytes
vmemoryuse       infinity kB

進め方がわかりません。問題を絞り込むためにどのように、またはどこを見ることができますか?

どんな助けでも大歓迎です。


一部の var 名を変更し、入力チェック コードを省略したスクリプトを次に示します。

#!/usr/bin/perl -w
use DBI;
use strict;

my $exitstatus = 0;
my $infile = shift;
open (INFILE, "$infile");

my $dbh = DBI->connect(
  'dbi:Oracle:sid=mysid;host=myhostname',
  'myusername',
  'mypassword',
  {
    RaiseError => 1,
    AutoCommit => 1
  }
) or die $DBI::errstr;

while (<INFILE>) {
  chomp;
  next if (/^#.*$/ || /^$/);
  my @columns = split /\t/;
  my ($var1, $var2, $var3) = @columns;
  eval {
    my $oProce = qq{
      BEGIN
        InsertStoredProc(
        field1 => $var1,
        field2 => $var2,
        field3 => $var3
        );
      END;
    };
    $dbh->do( $oProce );
  };
  if ( $@ ) {
    $exitstatus=1;
    warn "LINE: @columns\n";
    warn "Execution of stored procedure failed: $DBI::errstr\n";
    warn "################################################################################\n";
  }
}
$dbh->disconnect;
close INFILE;
exit $exitstatus;
4

2 に答える 2

4

関連性があるとは思いませんが、そのコードはかなり非効率的です。挿入された行ごとに SQL を解析しています。しない理由:

my $sth = $dbh->prepare('BEGIN InsertStoredProc(?,?,?); END;');
while (<INFILE>) {
  chomp;
  next if (/^#.*$/ || /^$/);
  my @columns = split /\t/;
  #my ($var1, $var2, $var3) = @columns;
  eval {
       $sth->execute(@columns);
    #my $oProce = qq{
    #  BEGIN
    #    InsertStoredProc(
    #    field1 => $var1,
    #    field2 => $var2,
    #    field3 => $var3
    #    );
    #  END;
    #};
    #$dbh->do( $oProce );
  };
  if ( $@ ) {
    $exitstatus=1;
    warn "LINE: @columns\n";
    warn "Execution of stored procedure failed: $DBI::errstr\n";
    warn "################################################################################\n";
  }
}

AutoCommit をオフにするもう 1 つの提案は、すべての行ではなく N 行ごとにのみコミットするため、コードを高速化します。AutoCommit を使用するとハングが発生する理由は、私には意味がありません。

ハングしているように見えるポイントについては、再現できる場合は DBI_TRACE=15=x.log で実行し、接続で ora_verbose => 6 を設定してみてください。ハングしたときのログ ファイルの最後にあるもの。

于 2012-11-08T09:26:42.570 に答える
0

AutoCommit なしで試しましたか? おそらく、多くのトランザクションを作成すると、Oracle はそれ以上のリクエストの処理を停止します。

100 行ごとに、データがなくなったときにコミットを試みます。

strace -p your_program_pid を使用して、スクリプトがどこで停止しているかを確認できます。

これがお役に立てば幸いです。

于 2012-11-08T08:12:17.387 に答える