如何使用Perl DBI在Oracle中超时“选择更新”

时间:2009-06-08 18:05:24

标签: perl oracle dbi

有一种简单的方法来超时SQL语句,这样它就会失败而不是等待(例如传递一个空的结果集或错误信息或其他任何东西)所以我可以让一份工作的资源保留失败并给另一个机会?我正在寻找到目前为止我忽略的一些DBI选项;发送SIGALRM给自己自杀并不是我的想法(尽管如果必须的话,我可能不得不求助于此。)

剪断的代码是伪造的,并且缩短到了极端,但我希望你能抓住漂移。

my $sql = "SELECT one, two, three FROM sometable WHERE this = ? AND that = ?";
my $sth = $self->make_handle( $sql );
eval {
    foreach my $this ( sort keys %needed_ressources ) {
        # vvv This is where the idle time is spent vvv
        $sth->execute( $this, $that ) or die( "DB connection gone?!" );
        # ^^^ This is where the idle time is spent ^^^
        my ( $one, $two, $three ) = $sth->fetchrow_array();
        unless( $one ) { # undefined record set == not found
            $self->{DB_HANDLE}->rollback();
            die( "$this not defined for $that!" );
        }
    }
    # If we haven't died so far, we can move on
    foreach... #similar loop here doing the actual update statement
    $self->{DB_HANDLE}->commit();
};
return( 1 ) unless $@;
return( undef );

以下是感兴趣的血腥细节:

在一个大规模并行数字运算的应用程序中,实现了一个使用oracle表的ressource锁定机制。每个作业都需要锁定许多用于读取的资源和/或要写入的许多资源,并且只有在成功获取所有锁定时才能启动。而不是耐心地等待资源被释放,工作应该失败并且稍后由他们的主人重新运行(这使得开放交易的数量保持在低水平,同时通过在实际紧缩的情况下获得更多的工作来提高绩效。)

当然,在实际更新表之前,每行都使用“SELECT ... FOR UPDATE”语句进行保留,因此Oracle使用行级锁定,并且可以在表上进行并发事务。为了进一步减少可能的竞争条件和死锁,所有作业首先选择其资源行,然后在执行更新之前使用相同的顺序对它们进行行锁定。

截至当前实现,这在大多数案例中都可以正常工作。但是,因为“选择更新”阻塞直到Oracle实际授予行锁定,所以仍然可能发生作业空闲等待其资源,并且我正在追求这些以更好地利用可用的CPU功率。可以等待一两秒钟,但不是十点或更多只是为了锁定。对于稍后 un 锁定,当然需要等待,因此将整个数据库连接设置为仅接受立即结果将不起作用。

我总是感谢 RTFM 答案,只要他们指出 M 中我应该 TF 的位置> R ; - ))

提前多多谢谢,
Olfan

2 个答案:

答案 0 :(得分:7)

我认为您需要FOR UPDATE子句上的NOWAIT参数。如果无法锁定记录,则选择将失败(“ORA-00054:资源繁忙并且使用NOWAIT指定获取”) 并且您可以根据需要处理异常。查看SQL Reference manual。这是11g,但现在几个版本的语法没有改变。

另一个选择是给一个等待的时间:“FOR UPDATE WAIT 3”等待3秒钟获取锁定而不是立即失败。

答案 1 :(得分:2)

实际上,SIGALRM毕竟不是那么糟糕。列出了一些选项here