3

我在使用连接到 Oracle 8 的 DBI 模块(版本 1.601)的 Perl 脚本时遇到问题。操作系统是 FreeBSD 7.0。

该脚本只是打开一个连接,循环遍历一个 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 的另一个建议也将加速您的代码,因为您将只提交每 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 回答