2011-01-08 17 views
5

Ho una tabella in SQL Server 2008 (SP2) contenente 30 milioni di righe, dimensioni della tabella 150 GB, ci sono un paio di colonne int e due colonne nvarchar (max): una contenente testo (da 1 -30000 caratteri) e uno contenente xml (fino a 100000 caratteri).L'aggiornamento della tabella richiede molto tempo

La tabella non ha chiavi primarie o indici (è una tabella di staging). Così sto eseguendo una query:

UPDATE [dbo].[stage_table] 
SET [column2] = SUBSTRING([column1], 1, CHARINDEX('.', [column1])-1); 

la query è in esecuzione per 3 ore (e non è ancora completato), che credo sia troppo lungo. È? Vedo che c'è una velocità di lettura costante di 5 MB/se una velocità di scrittura di 10 MB/s in un file .mdf.

Come posso scoprire perché la query è in esecuzione così a lungo? Il "server" è i7, 24GB di RAM, dischi SATA in RAID 10.

Aggiornato:

tabella contiene una colonna int, due (20) colonne nvarchar e due colonne (max) nvarchar. Colonna1 e Colonne2 nella clausola di aggiornamento sopra sono colonne nvarchar (20). Le colonne "grandi" non vengono aggiornate.

Grazie mille!

+0

Le colonne degli aggiornamenti sono indicizzate? – IamIC

risposta

3

Onestamente, si tratta di un'enorme quantità di lavoro che si sta facendo (ricerca di testo e sostituzione su 150 gigabyte). Se i dati di staging sono originati al di fuori del database, potresti prendere in considerazione l'esecuzione delle operazioni di testo in quel punto, senza alcun overhead del database.

+0

Grazie per la risposta. Ho aggiornato la domanda. La colonna1 e la colonna2 sono colonne di nvarchar (20), quindi il testo ricercato non è così grande, solo la tabella è enorme. – rrejc

+0

Sospetto che sia ancora vero che faresti meglio a farlo fuori dal database. C'è un sovraccarico nell'elaborazione e nell'aggiornamento di ciascuna di queste righe, non tanto quanto se si stesse operando sull'intera base di testo, ma ancora molto. –

1

Si sta facendo un po 'di manipolazione delle stringhe su un campo - qualcosa a cui SQL è notoriamente pessimo. Prendi in considerazione la possibilità di scrivere una funzione SQL CLR che fa ciò che ti serve e usarlo al posto di SUBSTRING([column1], 1, CHARINDEX('.', [column1])-1).

+0

Se non ci sono criteri di selezione, perché la mancanza di indici è importante? – sgmoore

+1

Non vedo come un indice possa migliorare la query. Deve solo essere una scansione completa della tabella. –

+2

Perché un indice dovrebbe accelerare questo UPDATE? Non c'è una clausola WHERE. In effetti, per questo UPDATE un indice rallenterebbe le cose (a causa del tempo necessario per aggiornare gli indici). –

0

Un modo pratico per verificare se qualcosa è fuori dall'ordinario è aggiornare solo alcuni dati. Scrivi una vista che seleziona le prime 10.000 righe ed esegui l'aggiornamento rispetto alla vista.

Se 10.000 righe si aggiornano in quello che ci si aspetterebbe essere "normale" per il proprio server, allora ne consegue che sono solo "molti dati da aggiornare".

Se questo piccolo aggiornamento sembra non troppo lungo, quindi indagare di più.

Almeno questo ti offre un buon banco di prova.

1

Un modo pratico per verificare se qualcosa è fuori dall'ordinario è aggiornare solo alcuni dati. Scrivi una vista che seleziona le prime 10.000 righe ed esegui l'aggiornamento rispetto alla vista.

Se 10.000 aggiornamenti in quello che ti aspetteresti di essere "normale" per il tuo server, seguiresti che sono solo "molti dati da aggiornare".

Se questi piccoli aggiornamenti sembrano non molto lunghi, quindi indagare di più.

Almeno questo ti offre un buon banco di prova.

1

Ci sono alcune opzioni qui. Ma senza ulteriori informazioni su ciò che si intende fare con i dati dopo l'esecuzione di questo aggiornamento, la risposta di Larry Lustig sembra la più appropriata. Ma seguono altre opzioni:

  • Creare colonna2 come colonna calcolata anziché colonna fisica.
  • Eseguire il calcolo mentre si estraggono i dati dalla tabella di staging (che è anche ciò che avverrebbe se si utilizza il punto precedente
  • colonna indice2 e quindi eseguire gli aggiornamenti in blocchi di 10.000 record o così dove colonna2 è nullo. Ciò manterrà la dimensione transazione implicita verso il basso, che è probabilmente quello che è attualmente uccidendo le prestazioni.
1

non ho fatto questo tipo di lavorazione in SQL Server, quindi non sono sicuro se il consiglio si applica completamente, ma sono abbastanza fiducioso da suggerirti di provarlo però.

Quello che faccio di solito in Oracle è di evitare completamente gli aggiornamenti durante l'elaborazione di TUTTE le righe in una situazione come quella che descrivi (utente singolo, evento batch).

O riesco a migrare la logica dall'istruzione di aggiornamento all'istruzione che ha inserito le righe. O se questo non è possibile, creo una nuova tabella e inserisco la logica di aggiornamento nell'elenco di selezione. Ad esempio, invece di fare

UPDATE [dbo].[stage_table] 
SET [column2] = SUBSTRING([column1], 1, CHARINDEX('.', [column1])-1); 

vorrei fare:

create table stage_table2 as 
    select column1 
     ,substring(column1, 1, charindex('.', column1)-1) as column2 
     ,column3 
     ,column4 
    from stage_table; 

drop table stage_table; 

alter table stage_table2 rename to stage_table; 
-- re-create indexes and constraints, optionally gather statistics 

Potrei anche farlo con query parallele e l'opzione NOLOGGING di generare molto poco redo e di annullare le modifiche a tutti, che avrebbe sovraperformare un aggiorna la dichiarazione con un margine così ampio che non è nemmeno divertente :) Ovviamente questo è dovuto agli interni di Oracle, ma penso che sarebbe possibile replicarlo anche con SQL Server. C'è qualcosa nella descrizione che potrebbe rendere questo un approccio meno efficiente. Avevi alcune colonne di testo molto grandi che dovresti "trascinare" nell'istruzione CTAS.

Inoltre, è necessario esaminare la configurazione dell'hardware perché non è adatta a gestire la quantità di dati che è stata generata. O c'è qualcosa che non va con la configurazione, o avete un sacco di altre attività in corso:

posso vedere che non v'è costante leggere velocità di 5 MB/s e scrittura velocità di 10MB/s a. file mdf.

Posso battere quello sul mio portatile di 2 anni della mia ragazza. Data una velocità di lettura di 5 Mb/se una tabella di 150 GB, sarebbero necessarie 8,5 ore per eseguire la scansione del tavolo una sola volta. Ciò presuppone che il database aggiunga un overhead dello 0%, che è non il caso.

Problemi correlati