2013-07-25 10 views
5

Ho un database molto grande - Sto lavorando con un sottoinsieme che è 350m righe, ma alla fine sarà circa 3b righe. Il mio intero obiettivo qui è quello di ottimizzare un particolare tipo di query su questo database, a scapito di praticamente tutto tranne la memoria. Il file db con cui sto lavorando in questo momento è compresso con blosc al livello 1, su PyTables versione 2.3.1 (Potrei aggiornarlo, se questo sarebbe d'aiuto). Ogni fila ha tredici voci - una voce tipica assomiglia a questo:ottimizzazione di una query table.where complessa() in pytables?

['179', '0', '1', '51865852', '51908076', '42224', '22', '2', '20', '22', '2', '0.0516910530103', '0.0511359922511'] 

Sono tutti numerica, ma non necessariamente dello stesso tipo. Attualmente sto memorizzandoli in una tabella PyTables, con questa definizione:

ind = tables.UInt16Col(pos=0) 
hap = tables.UInt8Col(pos=1) 
chrom = tables.UInt8Col(pos=2) 
hap_start = tables.Int32Col(pos=3) 
hap_end = tables.Int32Col(pos=4) 
hap_len = tables.Int16Col(pos=5) 
mh_sites = tables.Int16Col(pos=6) 
mh_alt = tables.Int16Col(pos=7) 
mh_n_ref = tables.Int16Col(pos=8) 
all_sites = tables.Int16Col(pos=9) 
all_alt = tables.Int16Col(pos=10) 
freq = tables.Float32Col(pos=11) 
std_dev = tables.Float32Col(pos=12) 

Non mi importa quanto tempo ci vuole per impostare questo database - sarò in ultima analisi, essere la creazione di una volta e poi basta accesso esso. Le mie domande sono della forma:

a = [ x[:] for x in hap_table.where('''(mh_sites == 15) & (hap_len > 25000) & (hap_len < 30000) & (freq > .38) & (freq < .4) & (std_dev > .3) & (std_dev < .4)''')] 

Fondamentalmente sto cercando per le voci che corrispondono a una particolare riga intorno ad una data tolleranza. Sul mio database più piccolo (350m righe), che query richiede 38 secondi se ho indicizzati tutti e quattro colonne che sto cercando on:

byteorder := 'little' 
chunkshape := (32768,) 
autoIndex := True 
colindexes := { 
    "hap_len": Index(6, medium, shuffle, zlib(1)).is_CSI=False, 
    "freq": Index(6, medium, shuffle, zlib(1)).is_CSI=False, 
    "std_dev": Index(6, medium, shuffle, zlib(1)).is_CSI=False, 
    "mh_sites": Index(6, medium, shuffle, zlib(1)).is_CSI=False} 

e 10 secondi se non lo faccio indice. Non sono sicuro di capire perché la query è più lenta sul database indicizzato ... forse l'indicizzazione crea un sovraccarico che non è necessario?

Come ho detto, il mio obiettivo è quello di ottimizzare questo tipo di query il più possibile, a scapito di praticamente tutto tranne l'utilizzo della memoria (voglio usare il 2G, e davvero non voglio usare più di circa 5G). Ho provato l'indicizzazione e non sembra funzionare. Tutte le mie query sono su un singolo valore di mh_sites, e ci sono solo circa 100 valori possibili, quindi ho pensato di dividerlo in più tabelle, quindi cerco solo un sottoinsieme dei dati in qualsiasi momento (anche se io Non sono completamente sicuro di come farlo, tranne mydata.root.table_1, mydata.root.table_2, ecc.). Ho anche pensato di provare a memorizzarlo come array, magari come un array float, e quindi convertire tutto il resto in int quando devo usarli? Se fa la differenza, le mie query di solito restituiscono tra 20k e 500k risultati.

Qualche suggerimento su come ottimizzare questa query?

risposta

5

Ho capito come rendere questo molto più veloce - e la mia soluzione potrebbe aiutare le altre persone quindi la sto postando qui.

Ero confuso su come funzionava l'indicizzazione in PyTables. Ho immaginato che un CSI avrebbe effettivamente ordinato i dati, ma non è questo il caso: una volta che aggiungi una serie di righe , esse sono sempre nell'ordine. Per me, valeva la pena di ordinare i dati prima di inserirli. I miei tempi di interrogazione sono diminuiti di 1-2 ordini di grandezza.

Questo spiega anche perché l'indicizzazione della tabella ha effettivamente aumentato il tempo di interrogazione - poiché le righe erano essenzialmente distribuite casualmente, avevo bisogno di leggere l'intero database per ogni query. Quindi non importava se i pytables potessero usare l'indice per capire quali blocchi erano necessari da leggere, perché era comunque necessario leggere tutti i blocchi. Quindi l'indice ha aggiunto solo un sovraccarico quando i dati sono stati non ordinati. Con una tabella ordinata, l'indice aiuta sicuramente.

+1

se il set di dati diventa troppo grande per l'ordinamento prima di accodare non è sempre possibile. In tal caso, è possibile creare un indice CSI e quindi copiare la tabella utilizzando la parola chiave sortby che quindi inserisce le righe nell'ordine corretto senza dover disporre del set di dati completo in memoria. Il tempo potrebbe essere un problema perché la copia del set in un modo ordinato richiede molto tempo.Tuttavia, in uno scenario in cui si scrive una volta e si esegue una query spesso, potrebbe valere la pena. –

+0

Questo è anche menzionato nella documentazione di PyTables: [Ottimizzazione: raggiungimento della velocità massima: tabelle ordinate e oltre] (http://www.pytables.org/usersguide/optimization.html#achieving-ultimate-speed-sorted-tables-and -al di là) – 153957

Problemi correlati