Подтвердить что ты не робот

Можно ли убить один запрос в оракуле без убийства сеанса?

Я хотел бы иметь возможность убить пользовательский запрос в Oracle 10.2.0.4, не убивая их весь сеанс. Это позволит завершить запрос, но не регистрировать этого пользователя вне их сеанса, чтобы они могли продолжать делать другие запросы. Это вообще возможно? Или это тупой молот, убивающий сеанс, единственный способ прекратить выполнение запроса?

4b9b3361

Ответ 1

Я нашел трюк. Я понятия не имею, насколько безопасно это играть, но оно действительно работает. Существует событие Oracle 10237, которое описывается как "имитировать ^ C (для целей тестирования)".

У вас должен быть SID и SERIAL # сеанса, который вы хотите прервать.

Вызовите SYS.DBMS_SYSTEM.SET_EV (sid, serial #, 10237, 1, ''), чтобы активировать событие в целевом сеансе. Любое выполняемое в настоящее время выражение должно быть прервано (получение "ORA-01013: пользователь запросил отмену текущей операции" ). Пока установлено событие, любые дальнейшие инструкции, которые пытается выполнить сеанс, немедленно завершаются с той же ошибкой.

Чтобы деактивировать событие, сделайте тот же вызов с четвертым параметром, установленным на "0". После этого сеанс сможет выполнять инструкции снова.

Обратите внимание, что целевой сеанс должен обнаружить, что событие установлено, что может занять время или, возможно, никогда не произойдет, в зависимости от того, что он делает. Поэтому вы не можете просто быстро включать и выключать событие. Вам нужно включить его, убедитесь, что указанное утверждение остановлено, затем отключите его.

Вот пример кода. Это предназначено для запуска как анонимный блок в SQLPlus, с соответствующими переменными замещения "sid" и "serial". Вы можете превратить его в хранимую процедуру с такими параметрами.

DECLARE
  l_status  v$session.status%TYPE;
BEGIN

  dbms_system.set_ev( &sid, &serial, 10237, 1, '');

  LOOP
    SELECT status INTO l_status FROM v$session
      WHERE sid = &sid and serial# = &serial;
    EXIT WHEN l_status='INACTIVE';
  END LOOP;

  dbms_system.set_ev( &sid, &serial, 10237, 0, '');
END;

Ответ 2

Я подозреваю, что это возможно, так как вы можете сделать это в TOAD. Пока выполняется запрос, открывается диалоговое окно "Отмена", которое вы можете нажать, чтобы остановить запрос.

Как это реализовано, я не знаю, но было бы очень интересно узнать об этом.

Если вы используете java, вы можете использовать метод java.sql.Statement cancel(), который должен это сделать. См. Здесь некоторые примечания и ограничения...

http://download.oracle.com/docs/cd/B14117_01/java.101/b10979/tips.htm#BACDAICJ

Ответ 3

Вы можете посмотреть ограничения ресурсов:

"Если пользователь превышает ограничение ресурса уровня вызова, тогда Oracle останавливает обработку оператора, откатывает оператор и возвращает ошибку. Однако все предыдущие операторы текущей транзакции остаются нетронутыми, а сеанс пользователя остается подключенным".

Предполагается, что причиной отмены SQL является ограничение ресурса, а не обновление неправильного набора строк (например). Я подозреваю, что вы не сможете повлиять на текущий запущенный SQL, добавив ограничение ресурса.

http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/security.htm#i13767
http://download.oracle.com/docs/cd/B19306_01/server.102/b14231/dbrm.htm#i1010776

Ответ 4

В идеале пользовательское приложение должно иметь возможность отменить запрос (через OCICancel или эквивалент).

В противном случае лучше всего использовать диспетчер ресурсов (если в Oracle EE), вы можете использовать DBMS_RESOURCE_MANAGER.SWITCH_CONSUMER_GROUP_FOR_SESS, чтобы установить целевой сеанс в группу потребителей CANCEL_SQL.

Другой взлом для отмены запроса других сеансов, который не работает с сеансами клиента sqlplus, должен был отправить срочный сигнал в процесс Oracle, используя kill -URG (это взлом, а не для повседневного использования).

Я написал о том, почему он работает здесь:

http://blog.tanelpoder.com/2010/02/17/how-to-cancel-a-query-running-in-another-session/