Как отменить длительную операцию базы данных? - PullRequest
26 голосов
/ 20 мая 2009

В настоящее время работает с Oracle, но также потребуется решение для MS SQL.

У меня есть графический интерфейс, который позволяет пользователям генерировать SQL, который будет выполняться в базе данных. Это может занять очень много времени, в зависимости от поиска, который они генерируют. Я хочу, чтобы GUI / приложение реагировало во время этого поиска, и я хочу, чтобы пользователь мог отменить поиск.

Я использую фоновый рабочий поток.

Моя проблема в том, что, когда пользователь отменяет поиск, я не могу прервать звонок в базу данных. Он ожидает завершения и может опрашивать свойство CancelationPending. Это не только тратит ресурсы базы данных, но и создает проблемы для моего кода.

Если пользователь нажимает «Поиск» по очень длинному запросу, затем нажимает «Отмена», а затем снова «Поиск» - первый поиск все еще выполняется в базе данных. Фоновый работник все еще занят, когда снова нажимает кнопку поиска. Единственное решение, которое у меня есть для решения этой проблемы, - сделать нового фонового работника.

Кажется, это очень уродливый способ делать вещи. База данных продолжает работать, я создаю новые экземпляры фоновых рабочих .... когда я действительно хочу ОСТАНОВИТЬ вызов базы данных и повторно использовать того же самого рабочего.

Как я могу это сделать?

Ответы [ 10 ]

11 голосов
/ 20 мая 2009

Если вы используете ADO.NET и поставщик данных SQL, взгляните на метод SqlCommand.Cancel. Это делает то, что вы ищете. Тем не менее, он пытается отменить, и отмена может занять некоторое время. По сути, именно SQL Server должен решить, когда удовлетворить ваш запрос на отмену. Когда запрос отменен, вы должны получить SqlException, который указывает, что операция была отменена пользователем. По-видимому, вы не хотите рассматривать это исключение как исключение и обрабатывать его специально, например, если SqlException вызвано отменой операции пользователем, просто проглотите ее.

8 голосов
/ 13 сентября 2010

Я также заметил команду. Отмена () на самом деле не прерывает команду. Для меня сработало закрытие соединения (транзакция отката, если вы его используете), когда пользователь прерывает работу. Это вызовет исключение в фоновом потоке во время выполнения команды, поэтому вам нужно перехватить его и проверить там свойство CancellationPending, а в этом случае исключить повторное исключение ...

// When aborting
worker.CancelAsync();
command.Connection.Close();

// In your DoWork event handler
...
catch (Exception)
{
    if (worker.CancellationPending)
    {
        e.Cancel = true;
        return;
    }
    else
    {
        throw;
    }
}

// And in your RunWorkerCompleted event handler
if (e.Error == null && !e.Cancelled)
{
    ...
}
5 голосов
/ 21 мая 2009

Я почти уверен, что это возможно - мы используем TOAD для Oracle, и он позволяет отменять долго выполняющиеся запросы , как описано здесь . Я не уверен, как они это делают.

3 голосов
/ 20 мая 2009

Я думаю, что лучшее решение, кажется, убивает сессии через таблицу мониторинга.

С Oracle вы можете сделать это, как говорит Burnsys

В Firebird 2.5 он будет выглядеть таким же

Я надеюсь, что нечто подобное существует в Ms SQL

3 голосов
/ 20 мая 2009

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

2 голосов
/ 20 мая 2009

Как насчет открытия нового соединения с базой данных, войдите в систему как sysdba и отправьте команду sid, serial # 'IMMEDIATE' ALTER SYSTEM KILL SESSION, указав SID процесса, который вы хотите завершить.

Чтобы получить sessionID: выберите sid из v $ mystat, где rownum = 1

Чтобы получить Serial #: выберите sid, serial # из v $ session, где sid =: SID

http://www.oracle -base.com / Статьи / Разное / KillingOracleSessions.php

РЕДАКТИРОВАТЬ: WW идея для не Войти в систему как sysdba здесь: http://forums.oracle.com/forums/thread.jspa?threadID=620578

2 голосов
/ 20 мая 2009

Если вы используете SQLCommand, вы можете попробовать вызвать его Cancel метод.

1 голос
/ 23 мая 2012

Я пробовал отменить и закрыть с ADO 2.8 и SQLOLEDB или собственным клиентом SQL Server. При отмене набор записей прекращает выборку данных, но в фоновом режиме чтение с сервера продолжается и потребляет память из приложения. В 32-битном приложении может случиться так, что через несколько минут вы получите сообщение «недостаточно памяти». Когда я закрываю набор записей (или соединение, с или без отмены ранее), ADO 2.8 ждет, пока все записи не будут выбраны.

Я не знаю, работает ли ADO.NET лучше, но я думаю, что после отмены / закрытия будет хорошей идеей отслеживать память и доступ к сети, чтобы убедиться, что ADO действительно прекращает чтение данных.

0 голосов
/ 11 сентября 2018

KILL SESSION был для меня единственным способом отменить длительный запрос. Я использую управляемый оракул, и OracleCommand.Cancel () работает несколько раз, но обычно он не работает. Также OracleCommand.CommandTimeout не соблюдается в соответствии с моими тестами. Некоторое время назад, когда я использовал неуправляемый оракул, при условии, что мне удалось отменить команды, но не больше с управляемой. Любой способ убить сессию был единственным вариантом. Запрос выполняется не в потоке пользовательского интерфейса, а в отдельном потоке. Команда отмены отправляется из потока пользовательского интерфейса. Это немного сложнее, потому что приложение использует посредник, используя WCF, но в конце дня я убиваю сессию. Конечно, при выполнении запроса мне нужно найти и сохранить сеанс, чтобы при необходимости убить его. Есть много способов найти sid и serial #, чтобы убить сеанс оракула, и я хочу потратить ваше время на объяснение того, что вы уже знаете.

0 голосов
/ 20 мая 2009

Я не думаю, что это возможно. Вот ссылка на обсуждение на веб-сайте Oracle по этой теме: http://forums.oracle.com/forums/thread.jspa?threadID=400492&start=15&tstart=0

...