Mysql: crea indice su 1,4 miliardi di record


9

Ho una tabella con 1,4 miliardi di dischi. La struttura della tabella è la seguente:

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

Il requisito è creare un indice sulla colonna text.

La dimensione del tavolo è di circa 34 G.

Ho provato a creare l'indice con la seguente dichiarazione:

ALTER TABLE text_page ADD KEY ix_text (text)

Dopo 10 ore di attesa, finalmente rinuncio a questo approccio.

Esiste una soluzione praticabile su questo problema?

AGGIORNAMENTO : è improbabile che la tabella venga aggiornata, inserita o eliminata. Il motivo per cui creare un indice nella colonna textè perché questo tipo di query sql verrebbe eseguito frequentemente:

SELECT page_id FROM text_page WHERE text = ?

AGGIORNAMENTO : ho risolto il problema partizionando la tabella.

La tabella è suddivisa in 40 pezzi su colonna text. Quindi la creazione dell'indice sulla tabella richiede circa 1 ora per il completamento.

Sembra che la creazione dell'indice MySQL diventi molto lenta quando le dimensioni della tabella diventano molto grandi. E il partizionamento riduce la tabella in tronchi più piccoli.


1
Cosa c'è di sbagliato nell'usare la normale CREATE INDEXaffermazione?

Suggerirei che questa domanda potrebbe essere migliore su ServerFault - è più un amministratore DB che una domanda di programmazione.
da lì

@Derk: il normale approccio CREATE INDEX è troppo lento. Devo completare l'attività entro 1 giorno.

1
Hmm ... Non penso che tu possa aggirare questo. La creazione dell'indice richiede che il DBMS esegua la scansione di tutti i record, raccolga i campi "di testo" e inserisca / modifichi i nodi / sottostrutture dell'albero corrispondenti. E questo richiede molto tempo per 34G ...
Chiccodoro,

Quanta memoria ha il tuo server DB? Hai configurato MySQL per utilizzare tutta quella memoria o si sta limitando?

Risposte:


4

Potrebbe essere il tuo sistema non è all'altezza del compito? Non utilizzo MySQL (qui SQL Server), ma conosco la sofferenza di indicizzare una tabella di voci da 800 milioni. Fondamentalmente .... hai bisogno dell'hardware giusto per questo (come in: molti dischi veloci). Ora uso quasi una dozzina di Velociraptor e le prestazioni sono eccezionali;)

I server SQL (non come MS SQL Server, ma come server di database che utilizzano SQL) vivono e muoiono con accesso al disco e i normali dischi non sono all'altezza del compito di operazioni più grandi.


Il mio dubbio è che la creazione dell'indice di solito è molto veloce se il conteggio dei record è piccolo; diciamo milioni. Ma quando il conteggio è di miliardi, la creazione dell'indice diventa così lenta. Sembra che la crescita del tempo sia esponenziale.

Non dovrebbe essere davvero. MySQL in generale ha dei limiti, ma non è un database di merda e sarebbe MOLTO male. La generazione dell'indice diventa più lenta, ma tramite log (n), non (n), quindi non dovrebbe essere così male.
TomTom,

4

È possibile che si desideri creare un indice sui primi (ad esempio, 10) caratteri del campo di testo.

Dai documenti:

È possibile creare indici che utilizzano solo la parte iniziale dei valori di colonna, utilizzando la sintassi col_name (lunghezza) per specificare una lunghezza del prefisso indice:

CREATE INDEX ix_text ON text_page (text(10))

4

Ho risolto il problema partizionando la tabella.

La tabella è suddivisa in 40 pezzi su colonna text. Quindi la creazione dell'indice sulla tabella richiede circa 1 ora per il completamento.

Sembra che la creazione dell'indice MySQL diventi molto lenta quando le dimensioni della tabella diventano molto grandi. E il partizionamento riduce la tabella in tronchi più piccoli.


Quindi 40 x 1 ora è meno di 10 ore?
symcbean,

3

Imposta sort_buffer_size su 4 GB (o quanto più puoi a seconda di quanta memoria hai).

In questo momento l'indice di creazione sta facendo un ordinamento ma poiché hai un sort_buffer_size da 32 MB, fondamentalmente sta schiacciando inutilmente il disco rigido.


Questi post sono praticamente in disaccordo con te: xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size e meglio ronaldbradford.com/blog/… Sembra che non sia un valore globale, è per query, quindi si consigliano 4 GB per query. Inoltre, quando supera i 256 KB, viene mappato mem su disco anziché essere memoria effettiva in memoria. Se lo mantieni piccolo richiede più passaggi, ma evita il disco (non si scambia).
Ry4an Brase,

3

Se non è necessario effettuare query come:

SELECT page_id FROM text_page WHERE text LIKE '?%';

Suggerirei di creare una nuova colonna hash e indicizzare la tabella per colonna. La dimensione generale della tabella + indice potrebbe essere molto più piccola.

UPD : A proposito, 1,4 miliardi di numeri di chiavi primari occupano circa 6 GB, ovvero la lunghezza media della stringa è inferiore a 30 caratteri, indicizzare su un prefisso potrebbe essere più preferibile.

Dovresti anche dare un'occhiata al motore di archiviazione MERGE .


2

Un modo per farlo è quello di creare una nuova tabella con l'indice impostato e copiare i dati nella nuova tabella.

Inoltre, assicurati di avere abbastanza spazio temporaneo.


1
Ho provato questo approccio. Dopo 10 ore, meno dell'1% dei dati è stato copiato nella nuova tabella.

1
Amico ... sono 1,4 miliardi di record. Non milioni, MILIARDI. Questo è molto. Ci vorrà un po 'a prescindere.

Se si sceglie di eseguire questo metodo, suddividere la copia in blocchi più piccoli. Dì circa 100 a 200 milioni per ogni copia.

1
@ decompilato, suddividendolo in blocchi più piccoli non farà nulla (in realtà, potrebbe renderlo meno efficiente). @Bryan, anche con 1,4 miliardi di dischi, non dovrebbero volerci 1.000 ore.

0

Nel caso ti stia ancora chiedendo come farlo al meglio, ti suggerirei di utilizzare uno strumento di alter table online.

Ce ne sono molti su Internet, uno dei più famosi è:

Abbiamo gli stessi problemi con i tavoli grandi (oltre 500 milioni di dischi) e l'alterazione è perfetta. Crea una nuova tabella tmp, aggiunge il trigger sulla tabella originale (per il nuovo aggiornamento / elimina / inserisci record) e nel frattempo copia tutti i record nella nuova tabella (con la nuova struttura)

In bocca al lupo!

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.