Каким-либо способом ускорить работу с огромным файлом (80 ГБ)?

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

Это работало в течение часа на довольно мощном сервере Linux, который в остальном не перегружен. Любая альтернатива grep? Что-нибудь о моем синтаксисе, которое можно улучшить (egrep, fgrep лучше?)

Файл на самом деле находится в каталоге, который используется совместно с другим сервером, но фактическое дисковое пространство является локальным, поэтому это не должно иметь никакого значения?

grep захватывает до 93% ЦП

zzapper
источник
8
В зависимости от вашего региона, -iпереключатель может замедлить процесс, попробуйте без него -iили с LC_ALL=C grep .... Кроме того, если вы используете только фиксированную строку, используйте grep -F.
Тор
5
Как упоминал @dogbane, использование переменной LC_ALL = C вместе с fgrep может ускорить ваш поиск. Я провел некоторое тестирование и смог добиться увеличения производительности на 1400% и написал подробную статью, почему это есть в моем посте об ускорении grep
JacobN
Мне любопытно - какой файл размером 80ГБ? Я хотел бы думать, что, когда файл становится таким большим, может быть лучшая стратегия хранения (например, ротация файлов журнала или иерархическая категоризация по разным файлам и папкам). Кроме того, если изменения происходят только в определенных местах файла (например, в конце), просто сохраните некоторые результаты grep из более раннего раздела, которые не меняются, и вместо того, чтобы использовать grep для исходного файла, используйте grep для сохраненного файла результатов.
Шридхар Сарнобат
Я остановился на github.com/google/codesearch - и индексация, и поиск молниеносны (написано на Go). cindex .чтобы проиндексировать вашу текущую папку csearch db_pd.Clients.
ccpizza
1
Если бы ваш файл был проиндексирован или отсортирован, это можно было бы сделать намного быстрее. Поиск в каждой строке по определению O (n), тогда как отсортированный файл можно найти, разделив его пополам - в этот момент вы будете говорить менее чем за секунду, чтобы искать свои 80 ГБ (следовательно, почему индексированная база данных 80 ГБ не требует времени вообще для простого SELECT, тогда как ваш grep занимает ... ну, столько, сколько нужно).
Чарльз Даффи

Ответы:

148

Вот несколько вариантов:

1) Префикс вашей команды grep с LC_ALL=Cиспользованием языкового стандарта C вместо UTF-8.

2) Используйте, fgrepпотому что вы ищете фиксированную строку, а не регулярное выражение.

3) Уберите -iопцию, если она вам не нужна.

Итак, ваша команда становится:

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

Также будет быстрее, если вы скопируете файл на RAM-диск.

кендырь
источник
5
это было НАМНОГО быстрее на порядок спасибо. Кстати, я добавил -n, чтобы получить номера строк. Также может быть -m для выхода после матча
zzapper
5
Вау, большое спасибо @dogbane отличный совет! Это привело меня в исследовательский туннель, чтобы выяснить, почему LC_ALL = C ускоряет grep, и это был очень поучительный опыт!
JacobN
7
Некоторым людям (не мне) нравится grep -Fбольше, чемfgrep
Уолтер Тросс
2
Я понимаю, что LANG=C(вместо LC_ALL=C) достаточно, и его легче набирать.
Уолтер Тросс
2
@ Адриан fgrep- это еще один способ писать grep -F, как я man fgrepвам скажу. В некоторых версиях manтакже говорится, что первое не рекомендуется для второго, но более короткая форма слишком удобна, чтобы умереть.
Уолтер Тросс 07
36

Если у вас многоядерный процессор, я бы действительно рекомендовал GNU parallel . Для параллельного поиска большого файла используйте:

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

В зависимости от ваших дисков и процессоров чтение больших блоков может быть быстрее:

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

Это не совсем понятно из вашего вопроса, но другие варианты grepвключают:

  • Опускание -iфлага.
  • Использование -Fфлага для фиксированной строки
  • Отключение NLS с помощью LANG=C
  • Установка максимального количества совпадений с -mфлагом.
Стив
источник
2
Если это реальный файл, используйте --pipepartвместо --pipe. Это намного быстрее.
Ole Tange
Это использование не поддерживает шаблон, включая пробел, нам нужно использовать его так: parallel --pipe --block 10M "/ usr / bin / grep -F -C5 -e 'Animal Care & Pets'"
zw963
Что означает <символ, предшествующий параллельной команде?
elcortegano
1
@elcortegano: Это то, что называется перенаправлением ввода-вывода . По сути, он считывает ввод из следующего файла. Подобно UUOC,cat file.sql | parallel ... но избегает этого . GNU parallel также имеет способ читать ввод из файла с помощью parallel ... :::: file.sql. НТН.
Стив
10

Некоторое тривиальное улучшение:

  • Удалите опцию -i, если можете, нечувствительность к регистру выполняется довольно медленно.

  • Заменить .на\.

    Единственная точка - это символ регулярного выражения, соответствующий любому символу, что также является медленным.

BeniBela
источник
3

Две линии атаки:

  • Вы уверены, что оно вам нужно -i, или у вас есть возможность от него избавиться?
  • У вас есть еще ядра для игры? grepявляется однопоточным, поэтому вы можете захотеть запустить больше из них с разными смещениями.
Ойген Рик
источник
1
< eightygigsfile.sql parallel -k -j120% -n10 -m grep -F -i -C 5 'db_pd.Clients'  

Если вам нужно искать несколько строк, grep -f strings.txt сэкономит массу времени. Вышесказанное является переводом того, что я сейчас тестирую. значения параметров -j и -n, казалось, лучше всего подходят для моего варианта использования. -F grep также имеет большое значение.

пользователь584583
источник