Da tutto ciò che riesco a vedere non sembra che i problemi siano legati agli indici.
La chiave sembra essere nel fatto che il campo nvarchar (max) contiene "lotti" di dati. Pensa a ciò che SQL deve fare per eseguire questo aggiornamento.
Poiché la colonna che si sta aggiornando è probabilmente più di 8000 caratteri è memorizzata fuori pagina, il che implica uno sforzo ulteriore nella lettura di questa colonna quando non è NULL.
Quando si esegue un batch di aggiornamenti 50000, SQL deve inserirlo in una transazione implicita per consentire il ripristino in caso di problemi. Per eseguire il rollback, è necessario memorizzare il valore originale della colonna nel log delle transazioni.
Assumendo (per semplicità) che ogni colonna contenga in media 10.000 byte di dati, ciò significa che 50.000 righe conterranno circa 500 MB di dati, che devono essere memorizzati temporaneamente (in modalità di ripristino semplice) o permanentemente (in completo ripristino modalità).
Non esiste alcun modo per disabilitare i registri poiché comprometterebbe l'integrità del database.
Ho eseguito un test rapido sul desktop lento del mio cane e l'esecuzione di batch pari a 10.000 diviene proibitivamente lenta, ma ridurre le dimensioni a 1000 righe, che implica una dimensione di registro temporanea di circa 10 MB, ha funzionato perfettamente.
Ho caricato un tavolo con 350.000 righe e ne ho contrassegnato 50.000 per l'aggiornamento. Questa operazione è stata completata in circa 4 minuti e, poiché è scalabile in modo lineare, dovresti essere in grado di aggiornare le tue 5 milioni di righe sul desktop lento del mio cane in circa 6 ore sul mio desktop da 2 GB da 1 processore, quindi mi aspetto qualcosa di molto meglio sul server rinforzato. da SAN o qualcosa del genere.
È possibile eseguire l'istruzione di aggiornamento come selezione, selezionando solo la chiave primaria e la grande colonna nvarchar e assicurarsi che venga eseguita alla velocità desiderata.
Ovviamente il collo di bottiglia potrebbero essere altri utenti che bloccano cose o contese sulla memoria o sul server, ma dato che non hai menzionato altri utenti, suppongo tu abbia il DB in modalità utente singolo per questo.
Come ottimizzazione, è necessario assicurarsi che i registri delle transazioni si trovino su un diverso disco fisico/gruppo di dischi rispetto ai dati per ridurre al minimo i tempi di ricerca.
Vedere anche: http://stackoverflow.com/questions/571750/make-sql-server-faster-at-manipulating-data-turn-off-transaction-logging –
Come stai facendo il '50K batch records at un aggiornamento del tempo? È con una procedura memorizzata? Se è così, puoi inserire il codice? – Fede
@ user356004: in rilettura non posso fare a meno di pensare che il tuo server sia sotto carico pesante o che non sia impostato correttamente: quei tempi sembrano molto alti. –