Jakikolwiek sposób na przyspieszenie odtwarzania dużego pliku (80 GB)?

113
 grep -i -A 5 -B 5 'db_pd.Clients'  eightygigsfile.sql

Działa to od godziny na dość potężnym serwerze linuxowym, który inaczej nie jest przeciążony. Jakaś alternatywa dla grepa? Coś w mojej składni, które można poprawić (egrep, fgrep lepiej?)

Plik faktycznie znajduje się w katalogu, który jest współdzielony z montowaniem na innym serwerze, ale rzeczywisty obszar dysku jest lokalny, więc nie powinno to robić żadnej różnicy?

grep pochłania do 93% procesora

zzapper
źródło
8
W zależności od lokalizacji -iprzełącznik może spowolnić proces, spróbuj bez -ilub z włączeniem LC_ALL=C grep .... Ponadto, jeśli grepujesz tylko dla ustalonego ciągu, użyj grep -F.
Thor
5
Jak wspomniał @dogbane, użycie zmiennej LC_ALL = C wraz z fgrep może przyspieszyć wyszukiwanie. Zrobiłem kilka testów i udało mi się osiągnąć wzrost wydajności o 1400% i napisałem szczegółowy artykuł, dlaczego jest to w moim poście o przyspieszeniu grep
JacobN
Ciekawe - jaki plik ma 80 GB? Chciałbym pomyśleć, że kiedy plik stanie się tak duży, może być lepsza strategia przechowywania (np. Rotacja plików dziennika lub hierarchiczna kategoryzacja w różnych plikach i folderach). Ponadto, jeśli zmiany występują tylko w niektórych miejscach pliku (np. Na końcu), po prostu zapisz niektóre wyniki grep z wcześniejszej sekcji, które się nie zmieniają i zamiast grepować oryginalny plik, grep zapisany plik wynikowy.
Sridhar Sarnobat
Zdecydowałem się na github.com/google/codesearch - zarówno indeksowanie, jak i wyszukiwanie są błyskawiczne (napisane w Go). cindex .aby zindeksować bieżący folder csearch db_pd.Clients.
ccpizza
1
Gdyby twój plik został zindeksowany lub posortowany, można by to zrobić znacznie szybciej. Przeszukiwanie każdej linii jest z definicji O (n), podczas gdy posortowany plik można przeszukiwać, dzieląc go na pół - w tym momencie będziesz rozmawiać w ciągu sekundy, aby przeszukać 80 GB (stąd dlaczego indeksowana baza danych 80 GB nie zajmuje w ogóle czasu dla prostego SELECT, podczas gdy grep zajmuje ... cóż, tak długo, jak to trwa).
Charles Duffy

Odpowiedzi:

148

Oto kilka opcji:

1) Przedrostek polecenia grep z, LC_ALL=Caby użyć ustawień regionalnych C zamiast UTF-8.

2) Używaj, fgrepponieważ szukasz stałego ciągu znaków, a nie wyrażenia regularnego.

3) Usuń -iopcję, jeśli jej nie potrzebujesz.

Więc twoje polecenie staje się:

LC_ALL=C fgrep -A 5 -B 5 'db_pd.Clients' eightygigsfile.sql

Będzie to również szybsze, jeśli skopiujesz plik na dysk RAM.

dogbane
źródło
5
to było DUŻO szybciej o rząd wielkości dzięki. BTW dodałem -n, aby uzyskać numery linii. Może też -m do wyjścia po meczu
zzapper
5
Wow wielkie dzięki @dogbane świetna wskazówka! To doprowadziło mnie do tunelu badawczego, aby dowiedzieć się, dlaczego LC_ALL = C przyspiesza grep i było to bardzo pouczające doświadczenie!
JacobN
7
Niektórzy ludzie (nie ja) lubią grep -Fwięcej niżfgrep
Walter Tross
2
Rozumiem, że LANG=C(zamiast LC_ALL=C) wystarczy i jest łatwiejszy do wpisania.
Walter Tross
2
@Adrian fgrepto inny sposób pisania grep -F, jak man fgrepCi powie. Niektóre wersje mantwierdzą również, że ta pierwsza jest przestarzała dla drugiej, ale krótsza forma jest zbyt wygodna, aby umrzeć.
Walter Tross,
36

Jeśli masz procesor wielordzeniowy, naprawdę poleciłbym równoległe GNU . Aby równolegle grepować duży plik:

< eightygigsfile.sql parallel --pipe grep -i -C 5 'db_pd.Clients'

W zależności od dysków i procesorów odczyt większych bloków może być szybszy:

< eightygigsfile.sql parallel --pipe --block 10M grep -i -C 5 'db_pd.Clients'

Nie jest to do końca jasne, ale inne opcje grepobejmują:

  • Upuszczenie -iflagi.
  • Używanie -Fflagi dla ustalonego ciągu
  • Wyłączanie NLS za pomocą LANG=C
  • Ustawienie maksymalnej liczby dopasowań za pomocą -mflagi.
Steve
źródło
2
Jeśli jest to rzeczywisty plik, użyj --pipepartzamiast --pipe. Jest znacznie szybsza.
Ole Tange,
To użycie nie obsługuje wzorca obejmującego spację, musimy użyć tego w następujący sposób: parallel --pipe --block 10M "/ usr / bin / grep -F -C5 -e 'Animal Care & Pets'"
zw963
Co to znaczy <znak poprzedzający polecenie równoległe?
elcortegano
1
@elcortegano: To co się nazywa I / O przekierowania . Zasadniczo odczytuje dane wejściowe z następującej nazwy pliku. Podobny do, cat file.sql | parallel ...ale unika UUOC . Równoległe GNU ma również sposób na odczyt danych wejściowych z pliku przy użyciu parallel ... :::: file.sql. HTH.
Steve
10

Niektóre trywialne ulepszenia:

  • Usuń opcję -i, jeśli możesz, niewrażliwość na wielkość liter jest dość powolna.

  • Zastąp .przez\.

    Pojedynczy punkt to symbol wyrażenia regularnego pasujący do dowolnego znaku, który również jest wolny

BeniBela
źródło
3

Dwie linie ataku:

  • czy na pewno potrzebujesz -i, czy masz możliwość się go pozbyć?
  • Czy masz więcej rdzeni do zabawy? grepjest jednowątkowy, więc możesz chcieć rozpocząć ich więcej z różnymi przesunięciami.
Eugen Rieck
źródło
1
< eightygigsfile.sql parallel -k -j120% -n10 -m grep -F -i -C 5 'db_pd.Clients'  

Jeśli chcesz wyszukać wiele ciągów, grep -f strings.txt oszczędza mnóstwo czasu. Powyższe jest tłumaczeniem czegoś, co obecnie testuję. wartości opcji -j i -n wydawały się działać najlepiej w moim przypadku użycia. -F grep również zrobił dużą różnicę.

user584583
źródło