2010-03-20 22 views
32

Qualcuno può dirmi come aggiungere una chiave di scala in MySQL? Ho 500.000.000 di righe in un database, trans, con le colonne i (INT UNSIGNED), j (INT UNSIGNED), nu (DOUBLE), A (DOUBLE). Provo ad indicizzare una colonna, ad es.MySQL: quanto tempo è necessario per creare un indice?

ALTER TABLE trans ADD KEY idx_A (A); 

e aspetto. Per un tavolo di 14.000.000 di righe ci sono voluti circa 2 minuti per l'esecuzione sul mio MacBook Pro, ma per l'intero mezzo miliardo, ci vogliono 15 ore e il conteggio. Sto facendo qualcosa di sbagliato, o sono solo ingenuo su come l'indicizzazione di un database si ridimensiona con il numero di righe?

+0

si potrebbe desiderare di guarda in split (database sharding) il tuo tavolo –

risposta

27

Ci sono un paio di fattori da considerare:

  • ordinamento è un'operazione N.log (N).
  • L'ordinamento per le righe 14M potrebbe adattarsi bene alla memoria principale; l'ordinamento con le righe di 500M probabilmente no, quindi l'ordinamento si riversa sul disco, il che rallenta enormemente le cose.

Poiché il fattore è di circa 30 dimensioni, il tempo di ordinamento nominale per il set di dati di grandi dimensioni sarebbe dell'ordine di 50 volte il tempo - in meno di due ore. Tuttavia, sono necessari 8 byte per il valore dei dati e circa altri 8 byte di overhead (è un'ipotesi - sintonizzati su mySQL se sai di più su ciò che memorizza in un indice). Quindi, 14 M × 16 ≈ 220 MB di memoria principale. Ma 500M × 16 ≈ 8 GB di memoria principale. A meno che la tua macchina non abbia molta memoria (e MySQL è configurato per usarla), il grosso tipo si sta riversando sul disco e ciò rappresenta il resto del tempo.

+1

Grazie mille, per me ha senso - ho solo 4 GB. Sembra che la suddivisione (partizionamento?) I dati come suggerito sopra abbia molto senso. – xnx

+0

hai diviso il tuo tavolo? quanto ci è voluto? – juanpastas

2

In base alla mia esperienza: se l'hardware è in grado di gestirlo, l'indicizzazione di tabelle di grandi dimensioni con MySQL di solito scala in modo lineare. L'ho provato con tabelle di circa 100.000.000 di righe fino ad ora, ma non su un notebook, principalmente su server potenti.

Suppongo che dipenda principalmente da fattori hardware, dal tipo di motore di tabella che si sta utilizzando (MyIsam, INNO o qualsiasi altra cosa) e un po 'se la tabella è altrimenti in uso in mezzo. Quando lo stavo facendo, l'utilizzo del disco di solito saliva alle stelle, a differenza dell'utilizzo della CPU. Non sono sicuro degli hard disk del MacBook, ma immagino che non siano i più veloci in circolazione.

Se si dispone di tabelle MyISAM, è possibile dare un'occhiata più da vicino ai file di indice nella directory della tabella e vedere come cambia nel tempo.

+0

Grazie per la rapida risposta, Björn. Ho seguito il tuo suggerimento. Io lo prendo i file # sql-a8_6.MYD (attualmente 7.455.506,432 mila byte) e # sql-a8_6.MYI (attualmente 2,148,865,024 bytes) sono la nuova versione del database in fase di costruzione e l'indice ho richiesto rispettivamente? Quindi se la tabella originale è trans.MYD (12,645,156,375 byte) Ho finito circa il 60%? Sta cominciando a sembrare che starei meglio dividendo l'enorme tavolo in tavoli da 20 o più piccoli. Grazie, Christian – xnx

+0

Nel complesso dovrebbe essere. Bene, tutto dipende da cosa vuoi fare con quella quantità di dati. 500.000.000 di righe sono molte, quindi se vuoi fare qualche report in seguito, prova a minimizzare i dati. O prova a dividerlo, o prendi un bottino per le funzionalità di partizionamento di MySQL (dalla versione 5.1). – Bjoern

5

In primo luogo, la definizione della tabella potrebbe fare una grande differenza qui. Se non sono necessari i valori NULL nelle colonne, definirli NOT NULL. Ciò farà risparmiare spazio nell'indice e presumibilmente tempo durante la sua creazione.

CREATE TABLE x ( 
    i INTEGER UNSIGNED NOT NULL, 
    j INTEGER UNSIGNED NOT NULL, 
    nu DOUBLE NOT NULL, 
    A DOUBLE NOT NULL 
); 

Per quanto riguarda il tempo necessario per creare gli indici, questo richiede una scansione di tabella e mostrerà come REPAIR BY SORTING. Dovrebbe essere più veloce nel tuo caso (vale a dire un enorme set di dati) per creare una nuova tabella con gli indici richiesti e inserire i dati in essa, in quanto ciò eviterà l'operazione REPAIR BY SORTING mentre gli indici sono costruiti in sequenza sull'inserto. C'è un concetto simile spiegato in this article.

CREATE DATABASE trans_clone; 
CREATE TABLE trans_clone.trans LIKE originalDB.trans; 
ALTER TABLE trans_clone.trans ADD KEY idx_A (A); 

Poi lo script l'inserto in pezzi (come da articolo), o eseguire il dump dei dati utilizzando MYSQLDUMP:

mysqldump originalDB trans --extended-insert --skip-add-drop-table --no-create-db --no-create-info > originalDB .trans.sql 
mysql trans_clone < originalDB .trans.sql 

Questo inserirà i dati, ma non richiederà ricostruzione di un indice (l'indice è costruito come ogni riga inserita) e dovrebbe essere completato molto più velocemente.

+1

Si noti che invece di eseguire 'mysqldump' e un ripristino che richiede almeno un blocco di lettura continua della tabella per la durata del processo, è possibile utilizzare [pt-online-schema-change] (http: //www.percona .com/doc/percona-toolkit/2.2/pt-online-schema-change.html) dal Percona Toolkit: si occuperà della creazione e copia dei dati in più passaggi, rimuovendo il requisito di blocco continuo. –

0

Quindi, teoricamente, se ordinamento passo è un (N) Funzionamento N.log, il partizionamento del vostro grande tavolo farebbe risparmiare tempo sul funzionamento

Circa il 30% di guadagno per una tabella di 500 000 000 righe partitionned in 100 file uguali: perché 500 000 000 * log (500 000 000) = 4 349 485 002 e 100 * (500 000 000/100 * LOG (500 000 000/100)) = 3 349 485 002

Problemi correlati