このUnixコマンドを最適化するには?

このUnixコマンドを最適化するには?

次のコマンドは結果を出力するのに約10分かかります。

find . -name "muc*_*_20160920_*.unl*" | xargs zcat |
    awk -F "|" '{if($14=="20160920100643" && $22=="567094398953") print $0}'| head

パフォーマンスをどのように向上させることができますか?

ベストアンサー1

これはすでにかなり最適化されています。詳細を知らないと、ボトルネックが何であるかを知ることは困難です。

  • ストレージタイプ(HD、SSD、ネットワーク、RAID)
  • 一致するファイルの数と平均サイズ
  • ディレクトリやその他の不一致ファイルの数
  • 1行あたりのフィールド数
  • 平均行長

どんな状況でもできること:

  • /がサポートしている場合はor-print | xargsに変更してください-exec cmd {} +。これは間違っているだけでなく、どの文字が空白なのかを調べるために文字をデコードし、高価な引用を行う必要があるため、コストがかかります。-print0 | xargs -r0findxargs-print | xargsxargs
  • ロケールをC(export LC_ALL=C)に変更しました。ここに含まれるすべての文字(|ファイルの内容の10進数、ファイル名のラテン文字、ピリオド、アンダースコアを含む)は移植可能な文字セットの一部であるため、文字セットがUTF-8または他のマルチバイト文字の場合は、C言語のシングルバイト文字セットこの言語に切り替えると、find多くの作業が節約されますawk
  • 部品をawk次のように単純化しますawk -F "|" '$14 == "20160920100643" && $22 == "567094398953"'
  • 出力をにパイプしているので、出力バッファリングを無効にして、できるだけ早くこれらの10行を出力できますhead。またはawk経由で使用できます。またはinを追加することもできます。gawkmawkfflush()if (++n == 10) exitawk

要約する:

(export LC_ALL=C
find . -name "muc*_*_20160920_*.unl*" -exec zcat {} + |
  awk -F "|" '$14 == "20160920100643" && $22 == "567094398953" {
    print; if (++n == 10) exit}')

CPUがボトルネックを引き起こしている場合は、マルチコアGNUシステムで次のことを試すことができます。

(export LC_ALL=C
find . -name "muc*_*_20160920_*.unl*" -print0 |
  xargs -r0P 4 -n 100 sh -c '
    zcat "$@" | 
      awk -F "|" "\$14 == "20160920100643" && \$22 == "567094398953" {
        print; fflush()}"' sh | head)

zcat | awk100ファイルのバッチで4つのジョブを並列に実行します。

タイムスタンプの場合は、以前20160920100643に最後に変更されたファイルを除外できます。 GNUまたはBSDのfind場合-newermt '2016-09-20 10:06:42'

行にフィールド数が多い場合は、行を分割して余りにもawk多くのフィールドを割り当てると$n不利益になります。最初の22フィールドのみを考慮するアプローチを使用すると、スピードを上げることができます。

grep -E '^([^|]*\|){13}20160920100643(\|[^|]*){7}\|567094398953(\||$)'

awkコマンドより 。 GNUを使用して並列方式では最初にライン出力にオプションをgrep追加するか、非並列方式では10回一致後に停止します。--line-buffered-m 10

要約すると、CPUにボトルネックがあり、システムに4つ以上のCPUコア、400以上のmuc *ファイルがあり、GNUシステム(通常はgrepGNUよりはるかに高速ですawk)を使用しています。

(export LC_ALL=C
find . -name "muc*_*_20160920_*.unl*" -newermt '2016-09-20 10:06:42' -print0 |
  xargs -r0P 4 -n 100 sh -c '
    zcat "$@" | 
      grep --line-buffered -E \
        "^([^|]*\|){13}20160920100643(\|[^|]*){7}\|567094398953(\||$)"
  ' sh | head)

並列アプローチでは、互いに混合されたコマンド出力を得ることができますgrep(ラインバッファリングを使用し、数キロバイト未満のラインを提供してもライン境界は維持する必要があります)。

おすすめ記事