2010-09-12 5 views
28

Un breve riepilogo di quello che è successo. Sto lavorando con 71 milioni di record (non molto rispetto ai miliardi di record elaborati da altri). Su un diverso thread, qualcuno ha suggerito che l'attuale configurazione del mio cluster non è adatta alle mie esigenze. La mia struttura della tabella è:Tabella con 80 milioni di record e l'aggiunta di un indice richiede più di 18 ore (o per sempre)! Ora cosa?

CREATE TABLE `IPAddresses` (
    `id` int(11) unsigned NOT NULL auto_increment, 
    `ipaddress` bigint(20) unsigned default NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=MyISAM; 

E ho aggiunto i 71 milioni di dischi e poi ha fatto un:

ALTER TABLE IPAddresses ADD INDEX(ipaddress); 

E 'stato 14 ore e l'operazione non è ancora stata completata. Su Google, ho scoperto che esiste un approccio ben noto per risolvere questo problema: partizionamento. Capisco che ho bisogno di partizionare il mio tavolo ora basato sull'indirizzo ip, ma posso farlo senza ricreare l'intera tabella? Voglio dire, attraverso una dichiarazione ALTER? Se sì, c'era un requisito che diceva che la colonna da partizionare doveva essere una chiave primaria. Userò l'id di questo indirizzo IP nella costruzione di una tabella diversa in modo che ipaddress non sia la mia chiave primaria. Come partizionare la tabella in base a questo scenario?

+1

I documenti di partizionamento di MySQL: http://dev.mysql.com/doc/refman/5.1/en/partitioning.html –

+1

il campo ID non è necessario. –

+0

@Seun: In tal caso, se voglio costruire una tabella che contiene per esempio, 'URI | ipaddress' e si desidera utilizzare l'id associato al IP address, Come sarò in grado di farlo? Stavo cercando di normalizzare una tabella diversa che richiedeva la creazione di questo tavolo in primo luogo. Eventuali suggerimenti? – Legend

risposta

34

Ok si scopre che questo problema era più di una semplice creazione di una tabella, indicizzarlo e dimenticare il problema :) Ecco cosa ho fatto nel caso in cui qualcun altro affronta lo stesso problema (ho utilizzato un esempio di indirizzo IP ma funziona per altri tipi di dati troppo):

Problema: la tabella ha milioni di voci ed è necessario aggiungere un indice molto veloce

Usecase: consideri la memorizzazione di milioni di indirizzi IP in una tabella di ricerca . Aggiungere gli indirizzi IP non dovrebbe essere un grosso problema, ma la creazione di un indice su di essi richiede più di 14 ore.

Soluzione: partizionare il tavolo utilizzando la strategia MySQL's Partitionin g

Caso # 1: Quando la tabella che si desidera non è ancora creata

CREATE TABLE IPADDRESSES(
    id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    ipaddress BIGINT UNSIGNED, 
    PRIMARY KEY(id, ipaddress) 
) ENGINE=MYISAM 
PARTITION BY HASH(ipaddress) 
PARTITIONS 20; 

Caso # 2: Quando la tabella si voglio è già stato creato. Sembra esserci un modo per utilizzare ALTER TABLE per farlo ma non ho ancora trovato una soluzione adeguata per questo. Invece, c'è una soluzione leggermente inefficiente:

CREATE TABLE IPADDRESSES_TEMP(
    id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    ipaddress BIGINT UNSIGNED, 
    PRIMARY KEY(id) 
) ENGINE=MYISAM; 

Inserisci i tuoi indirizzi IP in questa tabella. E quindi creare la tabella effettiva con le partizioni:

CREATE TABLE IPADDRESSES(
    id INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    ipaddress BIGINT UNSIGNED, 
    PRIMARY KEY(id, ipaddress) 
) ENGINE=MYISAM 
PARTITION BY HASH(ipaddress) 
PARTITIONS 20; 

E poi finalmente

INSERT INTO IPADDRESSES(ipaddress) SELECT ipaddress FROM IPADDRESSES_TEMP; 
DROP TABLE IPADDRESSES_TEMP; 
ALTER TABLE IPADDRESSES ADD INDEX(ipaddress) 

E ci si va ... indicizzazione sul nuovo tavolo mi ha preso circa 2 ore su una macchina 3.2GHz con 1GB RAM :) Spero che questo aiuti.

3

Si sta utilizzando MyISAM che viene ritirato a breve. Un'alternativa sarebbe InnoDB.

"InnoDB è un motore di archiviazione sicuro per le transazioni (compatibile con ACID) per MySQL che dispone di funzionalità di commit, rollback e ripristino di emergenza per proteggere i dati degli utenti.Il blocco a livello di riga InnoDB (senza escalation per i blocchi di granularità più grossolani) e le letture non bloccanti coerenti in stile Oracle aumentano la concorrenza e le prestazioni di più utenti. InnoDB memorizza i dati degli utenti negli indici cluster per ridurre l'I/O per le query comuni basate sulle chiavi primarie. Per mantenere l'integrità dei dati, InnoDB supporta anche i vincoli di integrità referenziale FOREIGN KEY. Si può liberamente mescolare tabelle InnoDB con tavoli da altri motori di archiviazione di MySQL, anche all'interno della stessa istruzione "\

http://dev.mysql.com/doc/refman/5.0/en/innodb.html

Secondo:.

http://dev.mysql.com/tech-resources/articles/storage-engine/part_1.html

, si dovrebbe essere in grado di passare tra i diversi motori, utilizzando un semplice comando alter che consente una certa flessibilità. Essa afferma inoltre che ogni tabella nel database può essere configurato in modo indipendente.

+0

Grazie per i suggerimenti. Tuttavia, attualmente sto esaminando una soluzione specifica per MyISAM anche se preparerò un piano per passare successivamente a InnoDB. – Legend

7

Creati Gli indici con MySQL sono lenti, ma non così lenti. Con 71 milioni di record, dovrebbero essere necessari un paio di minuti, non 14 ore. problemi possibili sono:

  • Non è stato configurato le dimensioni dei buffer di ordinamento e le altre opzioni di configurazione

un'occhiata qui: http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_myisam_sort_buffer_size

Se si tenta di generare un indice da 1 GB con 8 MB sorta di buffer è in corso prendere molti passaggi. Ma se il buffer è più grande della cache della CPU, diventerà più lento. Quindi devi testare e vedere cosa funziona meglio.

  • qualcuno ha un blocco sul tavolo
  • sistema IO succhia
  • il server è scambiando
  • ecc

come al solito iostat controllo, vmstat, i registri, ecc emettere un LOCK TABLE sul tuo tavolo per controllare se qualcuno ha un blocco su di esso.

FYI sul mio desktop a 64-bit di creare un indice su 10M BIGINTs casuali prende 17s ...

0

nella tabella. hai già inserito 71 miliardi di record. ora se vuoi creare partizioni sulla colonna chiave primaria della tua tabella, puoi usare l'opzione alter table. Un esempio è dato per il vostro riferimento.

CREATE TABLE t1 (
    id INT, 
    year_col INT 
); 

ALTER TABLE t1 
    PARTITION BY HASH(id) 
    PARTITIONS 8; 
5

Ho avuto il problema dove volevo accelerare la mia ricerca aggiungendo un indice. Il tavolo conteneva solo circa 300.000 dischi, ma ha anche impiegato troppo tempo. Quando ho controllato i processi del server mysql, ho scoperto che la query che stavo cercando di ottimizzare era ancora in esecuzione in background. 4 volte! Dopo aver ucciso quelle query, l'indicizzazione è stata fatta in un batter d'occhio. Forse lo stesso problema si applica alla tua situazione.

+1

mostra la lista dei processi; kill [query | connection] {process_id}; – BuzzCloudAU