2013-07-25 11 views
5

Mam bardzo dużą bazę danych - pracuję z podzestawem, który ma 350 m wierszy, ale ostatecznie będzie to około 3b wierszy. Moim głównym celem jest optymalizacja określonego rodzaju zapytania w tej bazie danych, kosztem prawie wszystkiego oprócz pamięci. Plik db, z którym teraz pracuję, jest kompresowany z blosc na poziomie 1, na PyTables w wersji 2.3.1 (mógłbym zaktualizować, gdyby to pomogło). Każdy wiersz ma trzynaście wpisy - typowy wpis wygląda następująco:optymalizowanie złożonego zapytania table.where() w pytables?

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

Oni wszyscy liczbowy, ale niekoniecznie tego samego typu. Jestem aktualnie przechowywanie ich w PyTables tabeli, z tą definicją:

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) 

I naprawdę nie obchodzi, jak długo to trwa do utworzenia tej bazy danych - Ja ostatecznie tworząc go raz, a potem po prostu dostępu to. Moje pytania są postaci:

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)''')] 

Zasadniczo szukam wpisów pasujących do konkretnego wiersza w obrębie danej tolerancji. Na moim mniejszej bazy danych (350m wierszach), że zapytanie trwa 38 sekund, jeśli mam indeksowane wszystkie cztery kolumny, które szukam na:

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} 

i 10 sekund, jeśli nie mam indeksu wcześniej. Nie jestem pewien, rozumiem, dlaczego kwerenda jest wolniejsza w indeksowanej bazy danych. Może indeksowanie tworzy obciążenie, które nie jest konieczne?

Tak jak powiedziałem, moim celem jest zoptymalizowanie tego typu zapytania w największym możliwym stopniu - kosztem praktycznie wszystkiego, oprócz użycia pamięci (chcę użyć około 2G i naprawdę nie chcę używać więcej niż około 5G). Próbowałem indeksowania i nie wydaje się działać. Wszystkie moje zapytania dotyczą jednej wartości mh_sites, a istnieje tylko około 100 możliwych wartości, więc pomyślałem o podzieleniu ich na wiele tabel, więc przeszukuję tylko podzbiór danych w dowolnym momencie (chociaż "nie jestem do końca pewien, jak to zrobić, poza mydata.root.table_1, mydata.root.table_2, itp.). Myślałem także o próbie przechowywania go w postaci tablicy - może tablicy typu float, a następnie konwersji wszystkiego na ints, kiedy trzeba z nich korzystać? Jeśli to robi różnicę, moje zapytania zwykle zwracają wyniki od 20 000 do 500 000.

Wszelkie sugestie dotyczące optymalizacji tego zapytania?

Odpowiedz

5

Dowiedziałem się, jak zrobić to o wiele szybciej - a moje rozwiązanie może pomóc innym, więc zamieszczam je tutaj.

Nie wiedziałem, jak działa indeksowanie w PyTables. Pomyślałem, że CSI rzeczywiście sortuje dane, ale tak nie jest - po dodaniu zestawu wierszy są zawsze w tej kolejności. Dla mnie warto było posortować dane przed ich wstawieniem. Moje czasy zapytania zmniejszyły się o 1-2 rzędy wielkości.

Wyjaśnia to również, dlaczego indeksowanie tabeli faktycznie zwiększyło czas zapytania - ponieważ wiersze były w zasadzie losowe, musiałem przeczytać całą bazę danych dla każdego zapytania. Nie miało więc znaczenia, czy firma pytables mogłaby użyć tego indeksu do określenia, które bloki należy odczytać, ponieważ i tak musiała czytać wszystkie bloki. Więc indeks został dodany narzut, gdy dane zostały nieposortowane. Przy sortowanym stole indeks zdecydowanie pomaga.

+1

, jeśli zbiór danych zostanie zbyt duży, aby sortować przed dołączeniem, nie zawsze jest możliwe. W takim przypadku można utworzyć indeks CSI, a następnie skopiować tabelę za pomocą słowa kluczowego sortby, które następnie wstawi wiersze we właściwej kolejności, bez konieczności posiadania pełnego zestawu danych w pamięci. Czas może być problemem, ponieważ kopiowanie zestawu w posortowany sposób zajmuje dużo czasu.Jednak w scenariuszu, w którym piszesz raz i często pytasz, może być warta kłopotów. –

+0

Jest to również wspomniane w dokumentacji PyTables: [Optymalizacja - Osiąganie maksymalnej prędkości: posortowane tabele i nie tylko] (http://www.pytables.org/usersguide/optimization.html#achieving-ultimate-speed-sorted-tables-and -poza) – 153957

Powiązane problemy