Grepping file besar (80GB) dengan cara apa pun untuk mempercepatnya?

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

Ini telah berjalan selama satu jam di server linux yang cukup kuat yang sebaliknya tidak kelebihan beban. Ada alternatif lain selain grep? Apa pun tentang sintaks saya yang dapat ditingkatkan, (egrep, fgrep lebih baik?)

File tersebut sebenarnya ada di direktori yang dibagikan dengan mount ke server lain tetapi ruang disk sebenarnya adalah lokal sehingga seharusnya tidak ada bedanya?

grep mengambil hingga 93% CPU

zzapper
sumber
8
Bergantung pada lokal Anda, -isakelar dapat memperlambat proses, coba tanpa -iatau dengan LC_ALL=C grep .... Selain itu, jika Anda hanya mencari string tetap, gunakan grep -F.
Thor
5
Seperti yang disebutkan @dogbane menggunakan variabel LC_ALL = C bersama dengan fgrep dapat mempercepat pencarian Anda, saya melakukan beberapa pengujian dan dapat mencapai peningkatan kinerja 1400% dan menulis artikel terperinci mengapa ini ada dalam posting grep saya yang mempercepat
JacobN
Saya penasaran - file apa yang berukuran 80GB? Saya ingin berpikir bahwa ketika sebuah file menjadi sebesar itu, mungkin ada strategi penyimpanan yang lebih baik (misalnya memutar file log, atau mengkategorikan secara hierarki ke dalam file dan folder yang berbeda). Juga, jika perubahan hanya terjadi di tempat-tempat tertentu dari file tersebut (misalnya di akhir), maka simpan saja beberapa hasil grep dari bagian sebelumnya yang tidak berubah dan alih-alih grep file asli, grep file hasil yang disimpan.
Sridhar Sarnobat
Saya memilih github.com/google/codesearch - baik pengindeksan maupun pencarian sangat cepat (ditulis dalam Go). cindex .untuk mengindeks folder Anda saat ini, lalu csearch db_pd.Clients.
ccpizza
1
Jika file Anda diindeks atau diurutkan, ini bisa dibuat jauh lebih cepat. Mencari setiap baris adalah O (n) menurut definisi, sedangkan file yang diurutkan dapat dicari dengan membagi dua - pada titik mana Anda akan berbicara kurang dari satu detik untuk mencari 80gb Anda (oleh karena itu mengapa database terindeks 80gb tidak membutuhkan waktu sama sekali untuk SELECT sederhana, sedangkan grep Anda membutuhkan ... yah, selama dibutuhkan).
Charles Duffy

Jawaban:

148

Berikut beberapa opsinya:

1) Awali perintah grep Anda dengan LC_ALL=Cmenggunakan lokal C, bukan UTF-8.

2) Gunakan fgrepkarena Anda mencari string tetap, bukan ekspresi reguler.

3) Hapus -iopsi, jika Anda tidak membutuhkannya.

Jadi perintah Anda menjadi:

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

Ini juga akan lebih cepat jika Anda menyalin file Anda ke disk RAM.

dogbane
sumber
5
itu JAUH lebih cepat dengan urutan besarnya, terima kasih. BTW Saya menambahkan -n untuk mendapatkan nomor baris. Juga mungkin -m untuk keluar setelah pertandingan
zzapper
5
Wow terima kasih banyak tip bagus @dogbane! Ini membawa saya ke terowongan penelitian untuk mencari tahu mengapa LC_ALL = C mempercepat grep dan itu adalah pengalaman yang sangat mencerahkan!
JacobN
7
Beberapa orang (bukan saya) suka grep -Flebih darifgrep
Walter Tross
2
Pemahaman saya adalah bahwa LANG=C(daripada LC_ALL=C) sudah cukup, dan lebih mudah untuk mengetik.
Walter Tross
2
@Adrian fgrepadalah cara lain untuk menulis grep -F, seperti yang man fgrepakan diberitahukan kepada Anda. Beberapa versi manjuga mengatakan bahwa yang pertama tidak digunakan lagi untuk yang terakhir, tetapi bentuk yang lebih pendek terlalu nyaman untuk mati.
Walter Tross
36

Jika Anda memiliki CPU multicore, saya sangat merekomendasikan GNU parallel . Untuk melakukan grep file besar secara paralel:

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

Bergantung pada disk dan CPU Anda, mungkin lebih cepat membaca blok yang lebih besar:

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

Ini tidak sepenuhnya jelas dari pertanyaan Anda, tetapi opsi lain untuk grepmencakup:

  • Menjatuhkan -ibendera.
  • Menggunakan -Fbendera untuk string tetap
  • Menonaktifkan NLS dengan LANG=C
  • Mengatur jumlah pertandingan maksimal dengan -mbendera.
Steve
sumber
2
Jika itu adalah file yang sebenarnya, menggunakan --pipepartbukan --pipe. Jauh lebih cepat.
Ole Tange
Penggunaan ini tidak mendukung pola termasuk spasi, kita perlu menggunakan seperti ini: parallel --pipe --block 10M "/ usr / bin / grep -F -C5 -e 'Animal Care & Pets'"
zw963
Apa artinya <karakter yang mendahului perintah paralel?
elcortegano
1
@elcortegano: Itu ini apa yang disebut I / O redirection . Pada dasarnya, ini membaca masukan dari nama file berikut. Mirip dengan cat file.sql | parallel ...tetapi menghindari UUOC . GNU paralel juga memiliki cara untuk membaca input dari file menggunakan parallel ... :::: file.sql. HTH.
Steve
10

Beberapa perbaikan sepele:

  • Hapus opsi -i, jika Anda bisa, case insensitive cukup lambat.

  • Ganti .dengan\.

    Satu titik adalah simbol regex untuk mencocokkan karakter apa pun, yang juga lambat

BeniBela
sumber
3

Dua baris serangan:

  • apakah Anda yakin, Anda membutuhkan -i, atau apakah Anda memiliki kemungkinan untuk menyingkirkannya?
  • Apakah Anda memiliki lebih banyak core untuk dimainkan? grepadalah single-threaded, jadi Anda mungkin ingin memulai lebih banyak di offset yang berbeda.
Eugen Rieck
sumber
1
< eightygigsfile.sql parallel -k -j120% -n10 -m grep -F -i -C 5 'db_pd.Clients'  

Jika Anda perlu mencari beberapa string, grep -f strings.txt menghemat banyak waktu. Di atas adalah terjemahan dari sesuatu yang sedang saya uji. nilai opsi -j dan -n tampaknya bekerja paling baik untuk kasus penggunaan saya. -F grep juga membuat perbedaan besar.

pengguna584583
sumber