Grepping ไฟล์ขนาดใหญ่ (80GB) ด้วยวิธีใดเพื่อเพิ่มความเร็ว?


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

สิ่งนี้ทำงานเป็นเวลาหนึ่งชั่วโมงบนเซิร์ฟเวอร์ลินุกซ์ที่มีประสิทธิภาพพอสมควรซึ่งไม่ได้โหลดมากเกินไป ทางเลือกอื่นสำหรับ grep หรือไม่? อะไรเกี่ยวกับไวยากรณ์ของฉันที่สามารถปรับปรุงได้ (เช่น egrep, fgrep ดีกว่าไหม)

ไฟล์ดังกล่าวอยู่ในไดเร็กทอรีที่แชร์กับการเมานต์ไปยังเซิร์ฟเวอร์อื่น แต่ดิสก์สเปซจริงเป็นแบบโลคัลจึงไม่ควรสร้างความแตกต่าง?

grep จับ CPU ได้มากถึง 93%


8
ทั้งนี้ขึ้นอยู่กับสถานที่ของคุณที่-iสวิทช์อาจชะลอตัวลงกระบวนการลองโดยไม่ต้องหรือ-i LC_ALL=C grep ...นอกจากนี้หากคุณจับเฉพาะสตริงคงที่ให้ใช้grep -F.
ธ .

5
ดังที่ @dogbane กล่าวถึงโดยใช้ตัวแปรLC_ALL = Cร่วมกับfgrepสามารถเพิ่มความเร็วในการค้นหาของคุณได้ฉันทำการทดสอบบางอย่างและสามารถเพิ่มประสิทธิภาพการทำงานได้ถึง1400%และเขียนบทความโดยละเอียดว่าทำไมสิ่งนี้จึงอยู่ในโพสต์grepของฉัน
JacobN

ฉันสงสัย - ไฟล์ขนาด 80GB คืออะไร? ฉันอยากจะคิดว่าเมื่อไฟล์ใหญ่ขนาดนั้นอาจมีกลยุทธ์การจัดเก็บที่ดีกว่านี้ (เช่นการหมุนไฟล์บันทึกหรือจัดหมวดหมู่ตามลำดับชั้นในไฟล์และโฟลเดอร์ต่างๆ) นอกจากนี้หากการเปลี่ยนแปลงเกิดขึ้นเฉพาะในบางตำแหน่งของไฟล์ (เช่นในตอนท้าย) ให้เก็บผลลัพธ์ grep บางส่วนจากส่วนก่อนหน้าที่ไม่เปลี่ยนแปลงและแทนที่จะ grep ไฟล์ต้นฉบับให้ grep ไฟล์ผลลัพธ์ที่เก็บไว้
Sridhar Sarnobat

ฉันตัดสินบนgithub.com/google/codesearch - ทั้งการจัดทำดัชนีและการค้นหานั้นรวดเร็วทันใจ (เขียนใน Go) เพื่อจัดทำดัชนีโฟลเดอร์ปัจจุบันของคุณแล้วcindex . csearch db_pd.Clients
ccpizza

1
หากไฟล์ของคุณถูกจัดทำดัชนีหรือจัดเรียงสิ่งนี้อาจทำให้เร็วขึ้นอย่างมาก การค้นหาทุกบรรทัดคือ O (n) ตามความหมายในขณะที่ไฟล์ที่เรียงลำดับสามารถค้นหาได้โดยแบ่งเป็นสองส่วน - ณ จุดที่คุณกำลังพูดถึงในไม่กี่วินาทีเพื่อค้นหา 80gb ของคุณ (ด้วยเหตุนี้ฐานข้อมูลที่จัดทำดัชนี 80gb จึงใช้เวลาไม่นานเลย สำหรับการเลือกแบบธรรมดาในขณะที่ grep ของคุณใช้เวลา ... เช่นกันตราบเท่าที่ใช้)
Charles Duffy

คำตอบ:


148

นี่คือตัวเลือกบางส่วน:

1) นำหน้าคำสั่ง grep ของคุณLC_ALL=Cเพื่อใช้ C locale แทน UTF-8

2) ใช้fgrepเนื่องจากคุณกำลังค้นหาสตริงคงที่ไม่ใช่นิพจน์ทั่วไป

3) ลบ-iตัวเลือกถ้าคุณไม่ต้องการ

ดังนั้นคำสั่งของคุณจะกลายเป็น:

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

นอกจากนี้ยังจะเร็วขึ้นหากคุณคัดลอกไฟล์ไปยังดิสก์ RAM


5
นั่นเร็วกว่ามากตามลำดับขนาดขอบคุณ BTW ฉันเพิ่ม -n เพื่อรับหมายเลขบรรทัด นอกจากนี้อาจจะออกหลังการแข่งขัน
zzapper

5
ว้าวขอบคุณมาก @dogbane เคล็ดลับที่ยอดเยี่ยม! สิ่งนี้ทำให้ฉันลงไปในอุโมงค์การวิจัยเพื่อค้นหาว่าเหตุใด LC_ALL = C จึงเร่งความเร็ว grepและมันเป็นประสบการณ์ที่กระจ่างแจ้งมาก!
JacobN

7
บางคน (ไม่ใช่ฉัน) ชอบgrep -Fมากกว่าfgrep
Walter Tross

2
ความเข้าใจของฉันคือLANG=C(แทนLC_ALL=C) ก็เพียงพอแล้วและพิมพ์ได้ง่ายกว่า
Walter Tross

2
@ เอเดรียนfgrepเป็นอีกวิธีหนึ่งในการเขียนgrep -Fดังที่man fgrepจะบอกคุณ บางรุ่นmanยังบอกว่ารุ่นหลังเลิกใช้ไปแล้ว แต่รูปแบบที่สั้นกว่านั้นสะดวกเกินไปที่จะตาย
Walter Tross

36

หากคุณมีซีพียูแบบมัลติคอร์ผมจะแนะนำGNU ขนาน ในการ grep ไฟล์ขนาดใหญ่ในแบบขนานให้ใช้:

< 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: นั่นคือสิ่งที่เรียกว่าI / O เปลี่ยนเส้นทาง โดยทั่วไปจะอ่านอินพุตจากชื่อไฟล์ต่อไปนี้ คล้ายกับcat file.sql | parallel ...แต่หลีกเลี่ยงUUOC GNU parallel ยังมีวิธีอ่านอินพุตจากไฟล์โดยใช้parallel ... :::: file.sql. HTH.
Steve

10

การปรับปรุงเล็กน้อย:

  • ลบอ็อพชัน -i ถ้าทำได้กรณีไม่คำนึงถึงตัวพิมพ์ค่อนข้างช้า

  • แทนที่.ด้วย\.

    จุดเดียวคือสัญลักษณ์ regex เพื่อจับคู่อักขระใด ๆ ซึ่งช้าเช่นกัน


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 ยังสร้างความแตกต่างอย่างมาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.