【问题标题】:Perl script using DBI module with Oracle 8 stops processing使用带有 Oracle 8 的 DBI 模块的 Perl 脚本停止处理
【发布时间】:2012-10-28 03:35:40
【问题描述】:

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

脚本只是打开一个连接,循环遍历一个 CSV 文件,一次插入一行/一行数据,然后关闭连接并退出。 cron 作业每 30 分钟执行一次此脚本,处理任何传入的 CSV 文件。有时,脚本会在中途停止处理(没有插入新数据,不会消耗更多的 CPU 时间),因此有必要将其终止。

CSV 文件似乎存在大小阈值。任何低于 35000 行的内容,脚本都会执行并正常退出。否则它会停止并且进程处于(看似)休眠/等待状态。

我只能通过 SQL*Plus 远程访问 Oracle8。检查了 Oracle v$session 表,发现这些停滞进程的连接没有关闭,所以可能达到了一些资源限制?在 FreeBSD 上运行“限制”会产生以下结果:

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;

【问题讨论】:

  • 请包含您的脚本的某些部分。
  • 将代码附加到原始帖子。让我知道你的想法。

标签: perl oracle unix freebsd dbi


【解决方案1】:

您是否尝试过不使用 AutoCommit?也许您创建了许多事务,而 Oracle 停止处理更多请求。

每 100 行尝试提交,当没有更多数据时。

您可以使用 strace -p your_program_pid 查看发生了什么,您的脚本在哪里停止。

希望对你有帮助。

【讨论】:

    【解决方案2】:

    不是我认为它相关,而是代码效率很低。您正在为插入的每一行解析 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。挂起时日志文件的末尾是什么。

    【讨论】:

    • 这样做的另一个优点是它使用参数化查询,因此任何值都不可能劫持查询。
    • 谢谢。我会尝试发布的所有建议。只是继承了这些系统,其中大部分都不是最理想的。
    猜你喜欢
    • 1970-01-01
    • 2013-04-06
    • 2013-04-17
    • 1970-01-01
    • 2014-12-31
    • 2010-11-02
    • 2016-11-01
    • 1970-01-01
    相关资源
    最近更新 更多