2009-05-20 9 views
23

Actualmente trabaja con Oracle, pero también necesitará una solución para MS SQL.Cómo cancelar una operación larga de la base de datos?

Tengo una GUI que permite a los usuarios generar SQL que se ejecutará en la base de datos. Esto puede llevar mucho tiempo, según la búsqueda que generen. Quiero que la GUI/aplicación responda durante esta búsqueda y quiero que el usuario pueda cancelar la búsqueda.

Estoy usando un hilo de trabajador de fondo.

Mi problema es que, cuando el usuario cancela la búsqueda, no puedo interrumpir la llamada a la base de datos. Espera hasta que se termine y luego, puede sondear la propiedad 'CancelationPending'. No solo esto desperdicia recursos en la base de datos, sino que crea problemas para mi código.

Si el usuario hace clic en 'Buscar' en una consulta muy larga, luego hace clic en 'Cancelar' y luego 'Buscar' otra vez - la primera búsqueda todavía está desapareciendo en la base de datos. El trabajador de fondo todavía está ocupado cuando vuelven a buscar. La única solución que tengo para este problema es crear un nuevo trabajador de segundo plano.

Parece una manera realmente fea de hacer las cosas. La base de datos sigue funcionando Estoy creando nuevas instancias de trabajadores en segundo plano ... cuando realmente quiero PARAR la llamada a la base de datos y volver a usar el mismo trabajador.

¿Cómo puedo hacer eso?

+1

Gracias por todas las publicaciones; Realmente no estoy seguro de cuál es la mejor respuesta; todo el voto ascendente parece haber venido de mí. Mis disculpas si tomé la decisión equivocada. –

+0

cualquier buen código de muestra? – Kiquenet

Respuesta

3

que podría tener el fuego trabajador de fondo de la llamada base de datos real en un subproceso diferente, y después comprobar periódicamente para ver si alguna de la llamada base de datos ha terminado , o se ha presionado cancelar, en ese punto podría eliminar el hilo de la base de datos. En realidad, esto no ayudaría a cargar la base de datos (ya que su consulta se ha enviado y aún se está procesando), pero libera los recursos locales relacionados con ella.

+1

No se puede eliminar el hilo que está en una llamada nativa. – ctusch

2

Si está usando un SQLCommand, puede intentar llamarlo al método Cancel.

2

¿Qué tal si abres una nueva conexión a la base de datos, inicias sesión como sysdba y envías un sid "ALTER SYSTEM KILL SESSION", serial # 'INMEDIATO' especificando el SID del proceso que quieres terminar.

Para obtener el Id.sesión: seleccione sid de v $ mystat donde rownum = 1

Para obtener Serial #: seleccione sid, serial # de v $ session donde sid =: SID

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

EDITAR: WW idea para no iniciar sesión como sysdba aquí: http://forums.oracle.com/forums/thread.jspa?threadID=620578

+2

Tener su inicio de sesión de aplicación como sysdba no es una buena idea desde el punto de vista de la seguridad. Sugeriría envolver este comando kill en un paquete PL/SQL que solo puede matar ciertas sesiones. –

+0

Es cierto que, en cualquier caso, es posible que necesite algunos privilegios especiales para ejecutar el paquete SQL, pero también debe establecer una nueva conexión para enviar el comando kill, por lo que se registrará en la base con privilegios especiales solo para finalizar la sesión. el resto de la aplicación puede usar el mismo usuario que antes. – Burnsys

10

Si está utilizando ADO.NET y proveedor de datos SQL, eche un vistazo al método SqlCommand.Cancel. Eso hace lo que estás buscando. Sin embargo, intenta cancelar y la cancelación puede llevar tiempo. Básicamente, depende de SQL Server decidir cuándo otorgar su solicitud de cancelación. Cuando se cancela la consulta, debe obtener una SqlException que indique que el usuario canceló la operación. Aparentemente, no desea tratar esta excepción como excepción y manejarla especialmente, como si SqlException se debe a que el usuario canceló la operación, simplemente tráguela.

3

Creo que la mejor solución parece matar sesiones a través de la tabla de supervisión.

Con Oracle se puede hacer como dice Burnsys

En Firebird 2.5 que se ve la same

espero algo existen similar en MS SQL

5

Estoy bastante seguro de que es posible - usamos TOAD for Oracle y le permite cancelar consultas de larga ejecución, as described here. Aunque no estoy seguro de cómo lo hacen.

6

También noté el comando. Cancelar() realmente no cancela el comando. Lo que funcionó para mí es cerrar la conexión (transacción de reversión si usa uno) cuando el usuario aborta. Esto levantará una excepción en el subproceso en segundo plano mientras que el comando se ejecuta, así que hay que cogerlo y comprobar la propiedad CancellationPending allí y no volver a lanzar la excepción en ese caso ...

// 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) 
{ 
    ... 
} 
+0

Estoy tratando de emplear esta sugerencia, pero obtener una excepción nativa que no puedo detectar me impide hacer esto de esta manera. ¿Tienes alguna experiencia con este método usando SQLCE? –

+0

No sé lo siento ... – Koen

+1

Querrá llamar a SqlConnection.ClearPool para asegurarse de que la conexión no vuelva al grupo ... http://objectmix.com/ado-dao-rdo-rds/ 358123-sqlconnection-clearpool-best-practice-command-timeout.html http://stackoverflow.com/questions/1145892/how-to-force-a-sqlconnection-to-physically-close-while-using-connection-pooling – user423430

1

He intentado tanto Cancelar y Cierre con ADO 2.8 y SQLOLEDB o cliente nativo de SQL Server. Con Cancel, el conjunto de registros deja de recuperar datos, pero en el fondo la lectura del servidor continúa y consume memoria de la aplicación. En una aplicación de 32 bits, puede ocurrir que reciba un mensaje de "falta de memoria" unos minutos más tarde. Cuando cierro el conjunto de registros (o la conexión, con o sin cancelar antes), ADO 2.8 espera hasta que se recuperen todos los registros.

No sé si ADO.NET lo hace mejor, pero creo que es una buena idea controlar la memoria y el acceso a la red después de Cancelar/Cerrar para asegurarse de que ADO realmente deje de leer datos.

Cuestiones relacionadas