Jak anulować długotrwałą operację bazy danych?

Obecnie pracuje z Oracle, ale będzie również potrzebował rozwiązania dla MS SQL.

Mam GUI, który pozwala użytkownikom generować SQL, który będzie wykonywany w bazie danych. Może to zająć bardzo dużo czasu, w zależności od Wyszukiwania, które generują. Chcę, aby GUI/aplikacja reagowała podczas tego wyszukiwania i chcę, aby użytkownik mógł anulować wyszukiwanie.

Używam wątku roboczego w tle.

Mój problem polega na tym, że gdy użytkownik anuluje wyszukiwanie, nie mogę przerwać połączenia do bazy danych. Czeka na zakończenie, a następnie może sprawdzić właściwość 'CancelationPending'. To nie tylko marnuje zasoby w bazie danych, ale stwarza problemy dla mojego kodu.

Jeśli użytkownik naciśnie "Szukaj" na bardzo długim zapytaniu, następnie kliknie "Anuluj", a następnie "Szukaj" ponownie - pierwsze wyszukiwanie nadal jest chugging away w bazie danych. Pracownik w tle jest nadal zajęty po ponownym naciśnięciu przycisku szukaj. Jedynym rozwiązaniem tego problemu jest stworzenie nowego tła pracownik.

To wygląda na naprawdę brzydki sposób na robienie rzeczy. Baza danych działa, tworzę nowe instancje pracowników w tle....kiedy naprawdę chcę zatrzymać połączenie z bazą danych i ponownie użyć tego samego pracownika.

Jak mogę to zrobić?

Author: Rob P., 2009-05-20

10 answers

Nie wydaje mi się to możliwe. Oto link do dyskusji na stronie Oracle na ten temat: http://forums.oracle.com/forums/thread.jspa?threadID=400492&start=15&tstart=0

 1
Author: Josh Curren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-20 17:06:45

Jeśli używasz ADO.NET i dostawca danych SQL, spójrz na SqlCommand.Metoda anulowania. To robi to, czego szukasz. Jednak próbuje anulować, A anulowanie może zająć trochę czasu. Zasadniczo to do SQL Server należy decyzja o przyznaniu żądania anulowania. Gdy zapytanie zostanie anulowane, powinieneś otrzymać wyjątek SqlException, który wskazuje, że operacja została anulowana przez użytkownika. Najwyraźniej nie chcesz traktować tego wyjątku jako wyjątku i obsługiwać go specjalnie tak, jakby SqlException wynika z anulowania operacji przez użytkownika, wystarczy ją połknąć.

 11
Author: Mehmet Aras,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-20 17:36:18

Zauważyłem też polecenie.Cancel() tak naprawdę nie przerywa polecenia. To, co działało dla mnie, to zamknięcie połączenia (transakcja rollback, jeśli go używasz), gdy użytkownik przerywa. Spowoduje to powstanie wyjątku w wątku w tle podczas wykonywania polecenia, więc musisz go złapać i sprawdzić tam właściwość CancellationPending, a nie rethrow wyjątku w takim przypadku...

// 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)
{
    ...
}
 7
Author: Koen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-10 14:57:06

Jestem prawie pewien, że jest to możliwe - używamy TOAD dla Oracle, i pozwala anulować długotrwałe zapytania, jak opisano tutaj . Ale nie jestem pewien, jak to robią.

 5
Author: JosephStyons,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-21 17:02:53

Worker w tle może wyłączyć rzeczywiste wywołanie bazy danych w innym wątku, a następnie okresowo sprawdzać, czy wywołanie bazy danych zostało zakończone lub czy zostało naciśnięte anulowanie, w którym to momencie można wyłączyć wątek bazy danych. W rzeczywistości nie pomogłoby to w załadowaniu bazy danych (ponieważ zapytanie zostało wysłane i jest nadal przetwarzane), ale zwalnia lokalne zasoby z nim związane.

 3
Author: GWLlosa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-20 17:09:01

Myślę, że najlepszym rozwiązaniem wydaje się zabić sesje za pomocą tabeli monitorowania.

Z Oracle możesz zrobić to jak mówi Burnsys

W Firebird 2.5 będzie wyglądał tak samo

Mam nadzieję, że coś podobnego istnieje w Ms SQL

 3
Author: Hugues Van Landeghem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-20 19:45:04

Jeśli używasz polecenia SQLCommand, możesz spróbować wywołać metodę Cancel .

 2
Author: stuartd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-20 17:17:47

A co z otwarciem nowego połączenia do bazy danych, zalogowaniem się jako sysdba i wysłaniem polecenia "ALTER system KILL SESSION' sid, serial# 'IMMEDIATE" określającego SID procesu, który chcesz zakończyć.

Aby uzyskać sessionID: select sid from v$mystat where rownum = 1

To get Serial#: select sid, serial# from v$session where sid=: SID

Http://www.oracle-base.com/articles/misc/KillingOracleSessions.php

EDIT: WW pomysł na nie Logowanie jako sysdba tutaj: http://forums.oracle.com/forums/thread.jspa?threadID=620578

 2
Author: Burnsys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-21 16:57:13

Próbowałem zarówno anulować, jak i zamknąć z ADO 2.8 i SQLOLEDB lub natywnym klientem SQL Server. Po anulowaniu zestaw rekordów przestaje pobierać dane, ale w tle odczyt z serwera jest kontynuowany i zużywa pamięć z aplikacji. W aplikacji 32-bitowej może się zdarzyć, że kilka minut później pojawi się komunikat "out of memory". Kiedy zamykam zestaw rekordów (lub połączenie, z anulowaniem lub bez), ADO 2.8 czeka aż wszystkie rekordy zostaną pobrane.

Nie wiem czy ADO.NET czy to lepiej, ale myślę, że to dobry pomysł, aby monitorować pamięć i dostęp do sieci po Cancel / Close, aby upewnić się, że ADO naprawdę przestaje odczytywać dane.

 1
Author: crk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-23 09:16:03

KILL SESSION był dla mnie jedynym sposobem na anulowanie długo działającego zapytania. Używam zarządzanego Oracle provided i OracleCommand.Cancel() działa kilka razy, ale zazwyczaj nie działa. Również OracleCommand.Zgodnie z moimi testami limit czasu nie jest przestrzegany. Jakiś czas temu, kiedy używałem niezarządzanej oracle pod warunkiem, że udało mi się anulować polecenia, ale już nie z zarządzanym. W każdym razie zabicie sesji było jedyną opcją. Zapytanie nie jest uruchamiane w wątku UI, ale na osobnej nici. Polecenie Anuluj jest wysyłane z wątku interfejsu użytkownika. Jest to trochę bardziej skomplikowane, ponieważ aplikacja używa środka za pomocą WCF, ale na koniec dnia zabijam sesję. Oczywiście podczas uruchamiania zapytania muszę znaleźć i zapisać sesję, aby w razie potrzeby ją zabić. Istnieje wiele sposobów, aby znaleźć Sida i serial# w celu zabicia sesji oracle i chcę marnować Twój czas wyjaśniając coś, co już wiesz.

 0
Author: Panagiotis Piperopoulos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-11 16:06:42