Как отключить выбор для обновления в Oracle с помощью Perl 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 );

Вот кровавые подробности для интересующихся:

В приложении, которое выполняет массовую параллельную обработку чисел, реализован механизм блокировки ресурсов, использующий таблицу оракула. Каждое задание должно заблокировать ряд ресурсов для чтения и / или ряд ресурсов для записи, и может запускаться только в том случае, если все блокировки были успешно получены. Вместо того, чтобы терпеливо ждать освобождения ресурсов, задания должны просто терпеть неудачу и повторно запускаться позже их мастером (это снижает количество открытых транзакций, одновременно повышая производительность за счет большего количества заданий, связанных с фактическим кризисом).

Конечно, перед фактическим обновлением таблицы каждая строка резервируется с помощью оператора «SELECT ... FOR UPDATE», поэтому Oracle использует блокировку на уровне строк, и в таблице могут происходить параллельные транзакции. Чтобы еще больше уменьшить возможные состояния гонки и взаимоблокировки, все задания сначала выбирают строки с их ресурсами, а затем блокируют их, используя тот же порядок, прежде чем выполнять обновление.

Что касается текущей реализации, это прекрасно работает в большинстве случаев. Но поскольку «Выбрать для обновления» блокируется до тех пор, пока Oracle фактически не предоставит блокировку строки, все еще может случиться так, что задание простаивает в ожидании своих ресурсов, и я стремлюсь к тому, чтобы лучше использовать доступную мощность процессора. Можно подождать секунду или две, но не десять или больше только для блокировки. Для снятия блокировки позже, конечно же, требуется ожидание, поэтому установка всего соединения с БД на прием только немедленных результатов не сработает.

Я всегда благодарен за ответы RTFM, если они указывают на место в M, которое у меня TF должно быть R < / strong> ;-))

Заранее большое спасибо,
Олфан


person Olfan    schedule 08.06.2009    source источник
comment
Что вы имеете в виду под самоубийством? Вы можете настроить обработчик SIGALRM на то, что хотите. Вы просто пытаетесь полностью избежать сигналов?   -  person jiggy    schedule 08.06.2009
comment
Я очень стараюсь иметь только сигналы обработки главного процесса. Может быть, Perl действительно справится с этим, но моя внутренняя структура мозга не готова к различным обработкам сигналов как в родительских, так и в дочерних процессах.   -  person Olfan    schedule 09.06.2009


Ответы (2)


Я думаю, вам нужен параметр NOWAIT в предложении FOR UPDATE. Если запись не может быть заблокирована, выбор не удастся («ORA-00054: ресурс занят и захватить с указанным NOWAIT»), и вы можете обработать исключение, как вам нужно. Ознакомьтесь с Справочным руководством по SQL . Это для 11g, но синтаксис уже не менялся для нескольких версий.

Другой вариант - дать время подождать: «FOR UPDATE WAIT 3», чтобы подождать 3 секунды, пока блокировка не будет получена, вместо немедленного отказа.

person DCookie    schedule 08.06.2009
comment
Это просто здорово, спасибо. Зачем возиться с Perl и DBI, если сам SQL уже дает нужный мне вариант? ;-) Он уже реализован и будет запущен в следующем окне возможных изменений. Еще раз спасибо. - person Olfan; 09.06.2009
comment
Perl / DBI имеет больший коэффициент для компьютерных фанатов ;-) - person DCookie; 09.06.2009
comment
Он жив, а время ожидания настраивается. Хотя большую часть времени, которое экономит это изменение, теперь просто тратится на ожидание накопителя (моя следующая цель ;-), общая загрузка ЦП (== исходная пропускная способность) выросла почти на 2%, что абсолютно оправдывает себя. - person Olfan; 12.06.2009

На самом деле, SIGALRM может быть не так уж и плох. Некоторые параметры перечислены здесь.

person Chris Simmons    schedule 08.06.2009
comment
Конечно ты прав. Но я действительно хочу, чтобы рабочие процессы не реализовывали свою собственную обработку сигналов, особенно когда она отличается от той, которую реализовал их родительский процесс. - person Olfan; 09.06.2009