วิธีการลบไฟล์เล็กๆ จำนวนๆมากๆ ให้เร็วแบบติดจรวด

เชื่อว่าหลายๆคนคงเคยเจอปัญหา อีเมลล์เตะลง Maildir/new จำนวนเยอะๆ

แต่ว่า rm -Rf folder ไปแล้วมันก็ยังช้าอยู่ …

ล่าสุดผมเจอไป 12 ล้านไฟล์ ลบกันข้ามวันยังไม่เสร็จ …

ไปค้นๆ blog ต่างประเทศ เจอช่องทางอื่นๆ หลายช่องทาง ที่มีความเร็ว ดังนี้ครับ

1.) ใช้ rsync

rsync -a --delete blank/ new/

ใช้ rsync --delete เพื่อลบ โดยระบุ source directory ให้เป็น blank เพื่อให้มันลบข้อมูลปลายทาง
การใช้ rsync จะเร็วกว่าแบบ find และคำสั่ง rm ครับ

2.) ใช้คำสั่ง find

find . -type f -delete

find . -print0 | xargs -0 rm -f

3.) ใช้ perl ในการลบ (เอาสคิปข้างล่างนี่ไปเปลี่ยนเอาได้เลย)

my $dir = ‘/home/username/Maildir/new’;
opendir(DIR,$dir) || die "Can’t open $dir : $!
";
my @files = readdir(DIR);
close(DIR);

foreach my $file(@files)
{
my $now = time;
my @stat = stat(“$dir/$file”);
#if ($stat[9] < ($now - 86400))

{

print “Deleting $dir/$file…”;
unlink(“$dir/$file”);
print "Done.
";

}

}

perl script นี่ให้เครดิตพี่ตี่ Metrabyte ครับ

จากการประเมิณแล้ว ใช้ perl จะไวที่สุดครับ

หวังว่าจะมีประโยชน์ครับ :slight_smile:

โอ้ ขอบคุณครับ ไปอ่านจากเมืองนอกมา เหมือนว่า perl จะเร็วสุดจริงๆด้วย

Ref: http://www.pc-freak.net/blog/how-to-delete-million-of-files-on-busy-linux-servers-work-out-argument-list-too-long/

แจ่มเลย

ปกติผมเปลี่ยนชื่อ folder ก่อน แล้วค่อยสั่งลบ folder ที่เปลี่ยนชื่อ สั่งเป็น background ทิ้งไว้ จะเสร็จตอนใหนก็ไม่สนใจละ

ผมใช้ rm -rf ลบข้ามวันมา ไฟล์ลดกะติ๋งเดียวเองครับ

เมื่อเช้าลองใช้ rsync ลบ จากไฟล์ 12 ล้านเหลือ 1 ล้าน ใช้เวลาประมาน 3-6 ชั่วโมง (ในสภาวะที่เครื่องทำงานหนัก)

ความแตกต่างไม่ได้อยู่ที่ perl หรือ bash ครับ แต่อยู่ที่ความแตกต่างของ rm และ unlink (ที่ใช้ใน perl) ตัวหลังจะทำงานเร็วกว่าตัวแรกมาก

script ข้างบน จะเป็น script ที่ไว้ลบไฟล์ที่อยู่ใน folder ทีละ folder ไม่สามารถ recursive เข้าไปในแต่ละ sub directory ได้ ซึ่งไม่สะดวกซักเท่าไหร่

ผมจะโม script นิดหน่อย ให้มันสามารถสั่งลบได้ทั้ง folder

#!/usr/bin/perldeldir($ARGV[0]);


sub deldir {
  my $dirtodel = pop;
  my $sep = '/'; #change this line to "/" on linux.
  opendir(DIR, $dirtodel);
  my @files = readdir(DIR);
  closedir(DIR);


  @files = grep { !/^\.{1,2}/ } @files;
  @files = map { $_ = "$dirtodel$sep$_"} @files;


  @files = map { (-d $_)?deldir($_):unlink($_) } @files;


  rmdir($dirtodel);
}

เวลาจะลบก็ใส่ agrument เข้าไปได้เลย