Как тайм-аут «выбрать для обновления» в Oracle с использованием Perl DBI - PullRequest
3 голосов
/ 08 июня 2009

существует простой способ тайм-аута оператора SQL , чтобы он не зависал вместо ожидания (например, доставил пустой набор результатов или сообщение об ошибке или что-то еще), чтобы я мог разрешить резервирование ресурсов для задания потерпеть неудачу и дать еще один шанс? Я ищу какой-то вариант DBI, который я пропустил до сих пор; отправка СИГАЛРМов себе для совершения самоубийства - это совсем не то, что я имею в виду (хотя, возможно, мне придется прибегнуть к этому, если бы мне пришлось).

Отрезанный код псевдоизображен и сокращен до крайности, но я надеюсь, что вы поймаете дрейф.

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 фактически не предоставит блокировку строки, может все же случиться так, что задание бездействует в ожидании своих ресурсов, и я стремлюсь к тому, чтобы лучше использовать доступную мощность ЦП. Можно подождать секунду или две, но не десять или больше только для блокировки. Для блокировки un позже требуется, конечно, ожидание, поэтому настройка всего соединения с БД на прием только немедленных результатов не будет работать.

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

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

Ответы [ 2 ]

7 голосов
/ 08 июня 2009

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

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

2 голосов
/ 08 июня 2009

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

...