SqlBulkCopy.WriteToServer non rispetta in modo affidabile BulkCopyTimeout

.net c# sqlbulkcopy sql-server-2008 timeout

Domanda

Devo contare le eccezioni sequenziali di timeout da SqlBulkCopy. Per verificare ciò, utilizzo un'applicazione esterna per avviare una transazione e bloccare la tabella di destinazione.

Solo alla prima chiamata SqlBulkCopy genera un'eccezione di timeout quando prevista. Abbiamo provato a utilizzare una connessione e una transazione esterne, oltre a utilizzare una stringa di connessione e una transazione interna. Con la connessione esterna e la transazione, l'attesa infinita non è mai stata nell'apertura della connessione o nell'inizio o .WriteToServer() della transazione, ma sempre in .WriteToServer() .

C'è un approccio a questo in cui SqlBulkCopy.WriteToServer() invierà in modo affidabile un'eccezione di timeout quando ha raggiunto il limite .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.
    }
}

Preferisco lasciare che le eccezioni esplodano piuttosto che gestirle nell'ambito del blocco using , ma posso sempre ripensare. Grazie mille per qualsiasi intuizione.

Aggiornamento 1:

Ancora nessuna risoluzione. Un comportamento interessante rilevato però - un normale SqlCommand genererà un TimeoutException come previsto durante lo stesso blocco che blocca il metodo SqlBulkCopy.WriteToServer in modo indefinito.

Ecco gli approcci che abbiamo provato - e che hanno fallito - a ottenere SqlBulkCopy.WriteToServer per generare in modo coerente i timeout quando previsto:

  • MARS (Multiple Active Result Sets) on / off
  • TableLock on vs. off
  • Destinazione come tabella heap rispetto a tabella indicizzata
  • Valori BulkTimeout più lunghi / più brevi (da 10 secondi a 5 minuti)
  • Transazioni interne o esterne

Per ora, come soluzione temporanea, sto alternando tra a) inserendo la chiamata WriteToServer in un wrapper asincrono in modo da poter cronometrare da solo, e b) solo chiamando WriteToServer una volta; dopo il timeout, attendere fino a quando un normale SqlCommand ha esito positivo prima di provare nuovamente WriteToServer. Utilizzando questi approcci, sono almeno in grado di mantenere il controllo del flusso di esecuzione.

Risposta accettata

Hai provato a passare l'opzione SqlBulkOptions.TableLock a SqlBulkCopy? Quell'opzione (citazione) significa che:

Ottenere un blocco di aggiornamento collettivo per la durata dell'operazione di copia di massa.

Quindi, se c'è un'altra elaborazione che blocca la tabella, impedirebbe il blocco e, in teoria, il timeout in modo affidabile.

Aggiornare:
Ho impostato il mio cablaggio di prova e non riesco a riprodurlo. Per bloccare la tabella, ho avviato una transazione in SSMS eseguendo un SELECT * FROM TargetTable WITH (HOLDLOCK) . Ho utilizzato lo stesso metodo BulkCopy incluso nella domanda, utilizzando le transazioni interne, con un timeout di caricamento di massa di 30 secondi. Ogni tentativo di eseguire la copia di massa è scaduto come previsto dopo 30 secondi. Succede poi quando eseguo il rollback della transazione SSMS.

Stavo usando SQL Server 2008 Express, .NET 3.5.

Non è qualcosa di simile dopo il primo tentativo, il timeout del caricamento di massa non viene passato correttamente? cioè non è in qualche modo impostato su "indefinito".

Aggiornamento 2:
Anche attivato il supporto di più set di risultati attivi nella stringa di connessione, ogni volta varia costantemente per me.


Risposta popolare

Ho avuto questo problema quest'ultimo e per risolvere questo problema impostare BulkCopyTimeout a zero.

bulkCopy.BulkCopyTimeout = 0;


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché