2009-10-19 17 views
5

Ho un programma C che estrae un'enorme fonte di dati (20 GB di testo non elaborato) e genera un sacco di INSERT da eseguire su una semplice tabella vuota (4 colonne integer con 1 chiave primaria). Impostazione come tabella MEMORY, l'intera attività viene completata in 8 ore. Dopo aver terminato, nella tabella sono presenti circa 150 milioni di righe. Otto ore sono un numero completamente dignitoso per me. Questo è un affare di una volta.Generazione di una tabella MySQL da 150 milioni di righe

Il problema nasce quando si cerca di convertire la tabella MEMORY di nuovo in modo che MyISAM (A) avrò la memoria liberata per altri processi e (B) i dati non saranno uccisi quando si riavvia il computer.

ALTER TABLE memtable ENGINE = MyISAM 

ho lasciato questa corsa ALTER TABLE query per più di due giorni ormai, e non è fatto. L'ho ucciso ora.

Se creo la tabella inizialmente come MyISAM, la velocità di scrittura sembra terribilmente scarsa (soprattutto perché la query richiede l'uso della tecnica ON DUPLICATE KEY UPDATE). Non riesco a spegnere temporaneamente le chiavi. Il tavolo diventerebbe oltre 1000 volte più grande se dovessi e poi dovrei rielaborare le chiavi ed essenzialmente eseguire un GROUP BY su 150.000.000.000 di righe. Umm, no.

Uno dei principali limiti da realizzare: la query INSERT UPDATE registra se la chiave primaria (un hash) esiste già nella tabella.

All'inizio di un tentativo di utilizzare rigorosamente MyISAM, ho una velocità approssimativa di 1.250 righe al secondo. Una volta che l'indice cresce, immagino che questo tasso aumenterà ancora di più.


Ho 16 GB di memoria installata nella macchina. Qual è il modo migliore per generare una tabella enorme che alla fine finisce come tabella MyISAM su disco, indicizzata?


Chiarimento: Ci sono molti, molti aggiornamenti in corso dalla query (INSERT ... ON DUPLICATE KEY UPDATE val=val+whatever). Questo non è, in alcun modo, un problema di discarica grezza. Il mio ragionamento per aver provato una tabella MEMORY era per l'accelerazione di tutte le ricerche sull'indice e le modifiche alla tabella che si verificano per ogni INSERT.

risposta

1

Mi spiace continuare a lanciare commenti (l'ultimo, probabilmente).

Ho appena trovato this article che fornisce un esempio di conversione di un grande tavolo da MyISAM a InnoDB, mentre questo non è quello che stai facendo, usa una tabella di memoria intermedia e descrive passare dalla memoria a InnoDB in modo efficiente - Ordinando la tabella in memoria il modo in cui InnoDB si aspetta di essere ordinato alla fine. Se non sei legato a MyISAM, potrebbe valere la pena dare un'occhiata dato che hai già creato una tabella di memoria "corretta".

+0

InnoDB andrebbe bene. Questo è molto intelligente ... Mi piace. Grazie per avermi inviato commenti. Lo apprezzo. :) – brianreavis

3

Se si intende renderlo un tavolo MyISAM, perché lo si sta creando in memoria in primo luogo? Se è solo per velocità, penso che la conversione in una tabella MyISAM annullerà qualsiasi miglioramento della velocità che si ottiene creando in memoria per iniziare.

Si dice che l'inserimento diretto in una tabella "su disco" è troppo lento (anche se non sono sicuro di come si sta decidendo quando il metodo attuale impiega giorni), potrebbe essere possibile disattivare o rimuovere i vincoli di unicità e quindi utilizzare una query DELETE in seguito per ristabilire l'unicità, quindi riattivare/aggiungere i vincoli. Ho usato questa tecnica durante l'importazione in una tabella INNODB in passato, e trovato anche con l'eliminazione successiva, nel complesso era molto più veloce.

Un'altra opzione potrebbe essere creare un file CSV invece delle istruzioni INSERT e caricarlo nella tabella utilizzando LOAD DATA INFILE (credo che sia più veloce degli inserti, ma al momento non riesco a trovare un riferimento) o utilizzando direttamente tramite il CSV storage engine, a seconda delle esigenze.

+0

Ho aggiornato la domanda per rispondere ad alcune delle vostre domande. Ho trovato fonti che sostengono che un inserto CSV viene eseguito più velocemente, ma sembra piuttosto semplice scaricare i dati in un CSV multi-gigabyte ** quindi ** caricarlo nel database. Questo aggiunge una quantità enorme di I/O del disco rigido lento al problema. – brianreavis

+0

Ma stai scaricando in un file SQL con un set di INSERTS comunque non lo sei. Non vedo come un file CSV sia diverso dall'IO? Ho aggiunto un paragrafo per spiegare un altro metodo che potrebbe risolvere il problema di "importazione in MyISAM è troppo lento". –

+0

Non riesco a rimuovere i vincoli di unicità. Sto usando 'ON DUPLICATE KEY UPDATE' per aggiornare un record se la chiave primaria (un hash) esiste già in grado. Se dovessi rimuovere il vincolo, la tabella sarebbe probabilmente più di 1000 volte la dimensione (e non è un'esagerazione). C'è una grande quantità di UPDATE in corso --- non è solo una discarica grezza nel database. – brianreavis

1

Non utilizzo mysql ma utilizzo server SQL e questo è il processo che utilizzo per gestire un file di dimensioni simili. Per prima cosa scarico il file in una tabella di staging che non ha vincoli. Quindi identifico ed elimino i duplicati dalla tabella di staging. Quindi cerco i record esistenti che potrebbero corrispondere e inserisco l'idfield in una colonna nella tabella di staging. Poi aggiorno dove la colonna del campo id non è nullo e inserisci dove è nullo. Uno dei motivi per cui faccio tutto il lavoro per sbarazzarmi dei duplicati nella tabella di staging è che significa meno impatto sulla tabella prod quando lo eseguo e quindi è più veloce alla fine. Il mio intero processo viene eseguito in meno di un'ora (e in realtà fa molto più di quanto descriva come devo denormalizzare e pulire i dati) e influenza le tabelle di produzione per meno di 15 minuti di quel tempo. Non mi devo preoccupare di aggiustare alcun vincolo o di eliminare indici o qualcosa del genere dato che eseguo la maggior parte della mia elaborazione prima che colpisca la tabella prod.

Considerare se un processo similare potrebbe funzionare meglio per voi. Potresti anche usare una sorta di importazione bulk per ottenere i dati grezzi nella tabella di staging (estraggo il file da 22 gig che ho in staging in circa 16 minuti) invece di lavorare fila per fila?

Problemi correlati