大量データの分割、切り出し処理

スクリプトで大量のデータ処理をしていてsplitが重いと感じたので
色々比較してみた。perlのsplitは正規表現での分割なので、そんなに早くは
無いだろうと思ったが、書き方によっても結構違うようだ。


対象データは300万行、600MB程度。
行単位で読み込んで該当フィールドのみを切り出して変数に格納。
以下、ループ内の処理だけ記述。

  • splitその1 所要時間20.0sec
 @list = split(/: /,$_);
 $result = $list[1];
  • splitその2 所要時間11.5sec
 $result = (split(/: /,$_))[1];
 $_ =~ /: (\w+?):/;
 $result = $1;
 $_ =~ /.*: (\w+?):.*/;
 $result = $1;
  • index+substr 所要時間7.0sec
 $pos1 = index($_,']: ');
 $pos1 += 3;
 $pos2 = index($_,': ',$pos1);
 $result = substr($_,$pos1,$pos2 - $pos1);
  • substrのみ 所要時間4.4sec
 #オフセットがずれると破綻
 $result = substr($_,16,12);
 $_ =~ /: (\w+?): .*?hoge=(.+?) /;
 $result1 = $1;
 $result2 = $2;
 $_ =~ /: (\w+?): /;
 $result1 = $1;
 $_ =~ /hoge=(.+?) /;
 $result2 = $1;
  • index+substr(複数) 所要時間10.7sec
 $pos1 = index($_,']: ');
 $pos1 += 3;
 $pos2 = index($_,': ',$pos1);
 $result1 = substr($_,$pos1,$pos2 - $pos1);
 $pos1 = index($_,'hoge=',$pos2);
 $pos1 += 5;
 $pos2 = index($_,' ',$pos1);
 $result2 = substr($_,$pos1,$pos2 - $pos1);


全データを分割して格納するような場合には、splitせざる得ないが
部分的に必要なだけの場合は、正規表現やindex+substrで切り出す方が
効率が良い様だ。正規表現も書き方さえ間違わなければそれほど遅くはならない。


切り出す対象が複数の場合も同様でindex+substrの方が早い。
対象の位置関係がはっきりしている場合は、探索位置が明示できる為
複数でも1回の正規表現マッチで行った方が効率が良い。


splitした場合でも、リストへの格納を避けて直接該当要素のみ
取り出せば多少は効率が良い。