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


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.


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.

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


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.

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ę.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.