巨大なファイル(80GB)を高速化する方法はありますか?


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

これは、他の方法では過負荷にならないかなり強力なLinuxサーバーで1時間実行されています。grepに代わるものはありますか?改善できる構文について何かあります(egrep、fgrepの方がいいですか?)

ファイルは実際には別のサーバーへのマウントと共有されているディレクトリにありますが、実際のディスクスペースはローカルなので、違いはありませんか?

grepは最大93%のCPUを取得しています


8
ロケールによっては、-iスイッチは、プロセスを遅らせることなしにしようとし-iたりしてLC_ALL=C grep ...。また、固定文字列のみをgrepする場合は、を使用しますgrep -F
トール

5
LC_ALL = C変数をfgrepと一緒に使用すると、@ dogbaneが検索を高速化する可能性があると述べました。私はいくつかのテストを行い、1400%のパフォーマンス向上を達成し、なぜこれが私のgrep高速化投稿にあるのか詳細な記事を書きました
JacobN

気になる-どのファイルのサイズが80GBですか?ファイルがこれほど大きくなったときに、より優れたストレージ戦略(たとえば、ログファイルのローテーション、または階層的に異なるファイルとフォルダーに分類すること)があると思います。また、変更がファイルの特定の場所(最後など)でのみ発生する場合は、前のセクションから変更されていないgrep結果を保存し、元のファイルをgrepする代わりに、保存された結果ファイルをgrepします。
Sridhar Sarnobat

私はgithub.com/google/codesearchで解決しました —インデックス作成と検索の両方が非常に高速です(Goで記述)。cindex .現在のフォルダにインデックスを付けるには、次にcsearch db_pd.Clients
ccpizza 2017年

1
ファイルがインデックス化またはソートされている場合、これは非常に高速になる可能性があります。すべての行の検索は定義によりO(n)ですが、ソートされたファイルはそれを2等分することでシークできます-その時点で80秒を検索するために1秒未満で話していることになります(そのため、80 GBのインデックス付きデータベースはまったく時間がかかりません単純なSELECTの場合、grepには...が必要ですが)。
Charles Duffy、

回答:


148

ここにいくつかのオプションがあります:

1)LC_ALL=CUTF-8の代わりにCロケールを使用するには、grepコマンドの接頭辞を付けます。

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 2013

7
以下のような一部の人(ない私)grep -F以上fgrep
ウォルターTross

2
私の理解は、LANG=C(の代わりにLC_ALL=C)十分であり、タイプしやすいということです。
Walter Tross

2
@Adrianはfgrep、書き込みに別の方法であるgrep -Fとして、man fgrepあなたを教えてくれます。の一部のバージョンではman、前者は後者には非推奨であるとも言われていますが、短い形式は死ぬにはあまりにも便利です。
Walter Tross 2016年

36

マルチコアCPUを使用している場合は、GNUパラレルをお勧めします。大きなファイルを並行してgrepするには:

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

ディスクとCPUによっては、大きなブロックを読み取る方が速い場合があります。

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

それはあなたの質問から完全に明確ではありませんが、他のオプションにgrepは以下が含まれます:

  • -i旗を落とす。
  • -F固定文字列にフラグを使用する
  • でのNLSの無効化 LANG=C
  • -mフラグとの一致の最大数を設定します。

2
実際のファイルの場合は、の--pipepart代わりに使用してください--pipe。それははるかに高速です。
Ole

この使用法はスペースを含むパターンをサポートしていません。次のように使用する必要があります:parallel --pipe --block 10M "/ usr / bin / grep -F -C5 -e 'Animal Care&Pets'"
zw963

<並列コマンドの前の文字はどういう意味ですか?
elcortegano

1
@elcortegano:これがI / Oリダイレクトと呼ばれるものです。基本的に、次のファイル名から入力を読み取ります。UUOCと同様ですがcat file.sql | parallel ...、回避します。GNU Parallelには、を使用してファイルから入力を読み取る方法もあります。HTH。parallel ... :::: file.sql
Steve

10

ささいな改善:

  • -iオプションを削除します。可能であれば、大文字と小文字を区別しないのはかなり遅いです。

  • 交換する.ことにより、\.

    単一のポイントは、任意の文字に一致する正規表現記号であり、これも遅い


3

2行の攻撃:

  • 本当に、あなたはが必要ですか、-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も大きな違いをもたらしました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.