AGGIORNA con JOIN su dischi da 100mm, come fare meglio? (in T-SQL)


11

Ho bisogno di aggiornare 100 milioni di record in una singola tabella, in effetti, normalizzando la tabella sostituendo il valore varchar di una colonna con semplicemente un ID. (Dico "sostituzione" ma in realtà sto scrivendo l'ID in un'altra colonna.)

Quello che sto cercando di ottenere è normalizzare il set di dati. I dati non ancora normalizzati non hanno indicizzazione. Il mio pensiero era che non avrei costruito indici sui valori grezzi, in attesa, invece di indicizzare le chiavi esterne che sostituiranno i valori varchar con valori tinyint dopo il completamento dell'aggiornamento.

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

sfondo

  • utilizzando MSSQL 2008 R2 su Server 2008 R2
  • il server ha 8 GB di RAM
  • il server ha un RAID10, 7200 RPM SATA (non eccezionale, lo so, in produzione questo leggerà solo i dati e non li scriverà; inoltre la recente carenza di HD lo ha reso necessario per i costi)
  • il server ha una doppia CPU Xeon quad-core
  • la macchina non sta facendo altro (attualmente dedicato agli sviluppatori, solo questo processo)
  • registrazione semplice attivata (? - ma registra comunque in modo da poter eseguire il rollback?)
  • si noti che la query fa riferimento a due diversi DB, per quello che vale
  • "larghezza" di un record nella tabella che viene aggiornata è 455 byte

Risorse durante l'esecuzione

  • la RAM fisica è al massimo
  • l'I / O del disco è al massimo
  • La CPU non fa quasi nulla (il choke point è I / O)
  • il tempo di esecuzione è stato di 14 ore e contando!

Sospetto alcune cose come se avessi bisogno di un indice sui dati grezzi, anche se lascerò cadere la colonna (AutoClassName) dopo gli aggiornamenti di normalizzazione. Mi chiedo anche se dovrei semplicemente buttare giù il tavolo un record alla volta anziché il JOIN, il che sembrava ridicolo al momento in cui ho iniziato questo, ma ora sembra che sarebbe stato più veloce.

Come dovrei cambiare più rapidamente la mia metodologia per i restanti aggiornamenti di normalizzazione (simili a questo)?

Risposte:


7

Stai provando a fare questo come un'unica transazione (molto grande). Invece, esegui l'aggiornamento in batch più piccoli.

Potresti anche beneficiare di:

  • Un indice temporaneo su AutoData.dbo.AutoClass.AutoClassName
  • Più RAM. Molto più RAM.

1
+1 Sono d'accordo con l'aggiornamento batch utilizzando la TOPclausola. Questo sarebbe il mio approccio.
Thomas Stringer,

Se eseguo UPDATE TOP allora avrò bisogno di una clausola WHERE (WHERE AutoClassID è NULL)? La clausola WHERE non introdurrebbe un nuovo hit di performance (una scansione della tabella che non sto facendo ora). Senza dubbio ciò ridurrebbe il problema di RAM che sto riscontrando con JOIN.
Chris Adragna,

La mia risposta è attesa da tempo, ma nel mio caso, SET ROWCOUNT si è rivelato il più efficace.
Chris Adragna,

10

Avrei un approccio diverso.

Invece di aggiornare le tabelle esistenti, crea una nuova tabella che contenga ciò di cui hai bisogno.

Questo sarà quasi sicuramente più veloce:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

Come attualmente scritto, ci sono molte operazioni logiche in corso:

  • Leggi tutti i valori di A.AutoClassName
  • Leggi tutti i valori di B.AutoClassName
  • Confronta i valori A e B.
  • Del set corrispondente, leggi tutti i valori di B.AutoClassID
  • Aggiorna i valori esistenti di A.AutoClassId in modo che corrispondano al valore B.AutoClassId tramite gli indici esistenti

Sembra un approccio semplice e gradevole, soprattutto dato il problema di I / O del disco che sto riscontrando. Grazie per aver risposto così rapidamente.
Chris Adragna,

1
Ti suggerisco di ricontrollare di avere abbastanza spazio libero nel tuo registro e file di dati. Se i file crescono automaticamente, le prestazioni si abbasseranno. Vedo spesso persone che eseguono grandi aggiornamenti una tantum e aumentano automaticamente il loro file di registro senza accorgersene.
Darin Strrait,

5

Scorrere la tabella una fila alla volta non sarà più veloce!

Come sospettato e confermato da te, questo sarà legato all'I / O: avere un disco, le letture, la scrittura, i registri delle transazioni e (qualsiasi) spazio di lavoro temporaneo saranno tutti in competizione per lo stesso I / O.

Il recupero semplice registrerà comunque le transazioni, ma il registro verrà cancellato da un checkpoint. È possibile che le dimensioni iniziali del registro e le impostazioni di crescita automatica stiano causando rallentamento di alcuni i / o - il registro delle transazioni dovrà crescere per adattarsi alle modifiche.

Hai provato a indicizzare il campo AutoClassName? Quanti sono i diversi valori di AutoClass?

Potrebbe essere necessario eseguire il batch degli aggiornamenti, in base alle limitazioni del proprio I / O. Quindi aggiorna 1 milione, controlla, ripeti ....


Esistono solo 15 diversi valori di AutoClass. I tuoi commenti confermano molti dei miei sospetti (e dolori!). Grazie per avermi risposto.
Chris Adragna,

3

Crea indici per i campi di unione.

Puoi sempre rilasciare gli indici quando hai finito.

Sarei molto sorpreso se gli indici non migliorassero significativamente le prestazioni di aggiornamento.


Sono sicuro che gli indici migliorerebbero. Suppongo che la domanda sia se migliorano più del tempo necessario per creare l'indice (solo per un uso). Probabilmente sì. :)
Chris Adragna,

3

Esporta come preferisci, crea una nuova tabella e importa nuovamente. Come bonus, dovresti avere una copia dei dati come backup, in caso di miracoli.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.