2010-02-05 12 views
8

Necesito contar las excepciones de tiempo de espera secuencial desde SqlBulkCopy. Para probar esto, utilizo una aplicación externa para iniciar una transacción & para bloquear la tabla de destino.SqlBulkCopy.WriteToServer no obedece confiablemente a BulkCopyTimeout

Solo en la primera llamada SqlBulkCopy lanza una excepción de tiempo de espera cuando se espera. Intentamos usar una transacción de conexión externa &, así como también usar una cadena de conexión y una transacción interna. Con la transacción de conexión externa &, la espera infinita nunca fue abrir la conexión o comenzar o comprometer la transacción, sino siempre al .WriteToServer().

¿Hay alguna forma de abordar esto mediante el cual SqlBulkCopy.WriteToServer() arrojará de manera confiable una excepción de tiempo de espera cuando haya alcanzado su límite .BulkCopyTimeout?

public void BulkCopy(string connectionString, DataTable table, int bulkTimeout) 
{ 
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
     connectionString, 
     SqlBulkCopyOptions.UseInternalTransaction)) 
    { 
    bulkCopy.BulkCopyTimeout = bulkTimeout;//e.g. 120 sec. 
    //... fill with data, map columns... 
    bulkCopy.WriteToServer(table); 
    // ^^^^ waits indefinitely, doesn't throw until *after* 
    //  the lock is released. 
    } 
} 

Prefiero dejar excepciones brotan en lugar de manejarlos en el ámbito del bloque using, pero siempre se puede volver a lanzar. Muchas gracias por cualquier idea.

Actualización 1:

Todavía no hay resolución. Sin embargo, se descubrió un comportamiento interesante: un SqlCommand normal lanzará una TimeoutException como se esperaba durante el mismo bloqueo que hace que el método SqlBulkCopy.WriteToServer se cuelgue indefinidamente.

Éstos son los enfoques que hemos probado - y que han fracasado - para obtener SqlBulkCopy.WriteToServer para lanzar consistentemente los tiempos de espera cuando se espera:

  • MARS (múltiples conjuntos de resultados activos) ON/OFF
  • TableLock en vs. off
  • Destino como tabla de montón vs. tabla indexada
  • valores BulkTimeout más cortos más largos/(10 segundos a 5 minutos)
  • interna vs transacción externa

Por el momento, como alternativa, estoy alternando entre a) poner la llamada WriteToServer en un contenedor asíncrono para que yo pueda temporizarlo, yb) llamar solo a WriteToServer una vez; después de los tiempos de espera, espere hasta que un SqlCommand regular tenga éxito antes de intentar WriteToServer nuevamente. Usando estos enfoques, al menos puedo mantener el control del flujo de ejecución.

+0

Solo para aclarar lo que sucede: inicia el proceso externo que bloquea la tabla de destino, luego prueba una copia masiva y se agota el tiempo esperado. A continuación, intente de nuevo la copia masiva (el proceso externo todavía tiene bloqueo en la tabla) pero esta vez no se agota el tiempo de espera. – AdaTheDev

+0

@AdaTheDev, sí, eso es exactamente correcto. El proceso externo inicia una transacción, ejecuta un comando de actualización sin cláusula where y espera a que el usuario ingrese para deshacer la transacción. El proceso de copia masiva está diseñado para volver a intentarlo varias veces, con diferentes acciones (alerta, pausa, conmutación por error) en función del número de tiempos de espera experimentados. –

+0

Ver mi última actualización - no se puede reproducir :( – AdaTheDev

Respuesta

4

¿Ha intentado pasar la opción SqlBulkOptions.TableLock a SqlBulkCopy? Esa opción (presupuesto) significa que lo hará:

Obtenga un bloqueo de actualización masiva para la duración de la operación de copia masiva .

Por lo tanto, si hay otro procesamiento que bloquea la mesa, evitaría que se ganara el bloqueo y, en teoría, se agotaría el tiempo de espera.

Actualización:
creé mi propio instrumento de prueba y no pueden reproducirse. Para bloquear la mesa, comencé una transacción en SSMS haciendo un SELECT * FROM TargetTable WITH (HOLDLOCK).Usé el mismo método BulkCopy que incluyó en la pregunta, usando transacciones internas, con un tiempo de espera de carga masiva de 30 segundos. Cada intento de hacer la copia masiva agota el tiempo esperado después de 30 segundos. Luego tiene éxito cuando deshago la transacción SSMS.

Estaba usando SQL Server 2008 Express, .NET 3.5.

¿No es algo así como después del primer intento, el tiempo de espera de carga masiva no se está pasando correctamente? es decir, de alguna manera no se establece en "indefinido".

Actualización 2:
también cambió en múltiples conjuntos de resultados activos apoyo en la cadena de conexión, siendo constantemente el tiempo de espera para mí cada vez.

+0

@AdaTheDev: sugerencia lógica, gracias. Acabo de probarlo, además he añadido un bloque 'try {} catch {}' alrededor de 'WriteToServer()' que acaba de llamar a 'bulkCopy.Close() 'luego vuelve a surgir. (Eso no debería ser necesario ya que SqlBulkCopy está en un bloque' using {} ', pero me estoy desesperando.) Desafortunadamente,' WriteToServer() 'todavía cuelga indefinidamente la segunda vez –

+0

Hmm, no puedo pensar en otra cosa en este momento - me desconcertó. Trataré de hacer una prueba con un arnés para reproducir – AdaTheDev

+0

Sí, me preguntaba si la agrupación de conexiones .NET podría tener algo que ver con eso , ya que he estado ejecutando el arnés de prueba y los procesos de inserción masiva en la misma máquina. Intenté su enfoque de bloqueo en SSMS, y todavía ocurre. Básicamente, llamo al método desde mi bloque de código en un bucle con un 3 Pausa de 0 segundos entre iteraciones. Imprimo el valor de BulkCopyTimeout en la consola justo antes de llamar a WriteToServer, por lo que estoy seguro de que el valor es coherente. ¡Misterioso! Acabo de encontrar algo sobre Conjuntos de resultados activos múltiples que posiblemente afecten los tiempos de espera. Se actualizará cuando descubra más. ¡Gracias! –

1

Tuve este problema más tarde y para resolver este problema establecí BulkCopyTimeout en cero.

bulkCopy.BulkCopyTimeout = 0; 
+0

En este caso, el problema es que bulkCopy * no está * agotado. Quiero arrojar para poder atrapar y contar las excepciones de tiempo de espera. Luego puedo evaluar si ha habido suficientes para indicar un problema grave. –

Cuestiones relacionadas