• 締切済み

Perlのデータファイルの運用について

現在Perlでソフトの管理プログラムを作っています。 1万件くらいまではまま順調に動いていたのですが 現在1万5千件くらいになって表示的にはそこそこ高速なのですが サーバー(ドリームホストの一番安いの・・・すいませんケチで)が 月に1度程度、極端に遅くなります。 どうも私の巨大データに問題が有るようなのですが・・・ で、サーバーの負荷をすこしでも減らしたいと思っているのです。 現在、検索の場合等は、全1万5千件余りのデーターを @all_data=<DATA>; で全読みし、各行の照合作業をした後、結果を出力しています。 これを1000件ごとのファイルに分割し、 1枚目ファイルオープン→@all_data=<DATA>;→結果収集、 2枚目ファイルオープン→@all_data=<DATA>;→結果収集、            ・             ・            ・ 15枚目ファイルオープン→@all_data=<DATA>;→結果収集、 で、結果を出力 の様に変更した方がサーバー負荷(CPU使用率やメモリー消費)は 少なくなる物でしょうか? または1行づつ照合作業し、結果を出力、 と言う手も有ると思うのですが・・・。 余り詳しくないので・・・出来ましたら素人向けの回答を背宜しくお願いします。

  • Perl
  • 回答数3
  • ありがとう数12

みんなの回答

  • ybnormal
  • ベストアンサー率50% (220/437)
回答No.3

まずは、メモリのサイズとファイルのサイズが明確でないと、遅くなる理由があなたのプログラムのせいなのかどうかはわかりません。件数が一万件から一万5千件になった程度(50%増)で極端に性能が落ちることはあまり考えられません。よっぽどメモリが小さいか、件数の増加とともに処理量が指数関数的に増えるような処理をしているかのどちらかです。 月に一度遅くなるということですが、あなたのプログラムは常時走っているのですか? 1000件に分割した場合、メモリ消費は減りますが、テキストを処理している間のCPUの使用効率は変わりません。1000件であろうと10000件であろうと同じ処理をしているわけですから、実行されている命令列は同じあるいは非常に似ています。似たような命令列が実行されるのであれば、実行中のCPUの使用効率に変化はほとんどありません。ただ、ファイルを分割した場合は、新たにファイルを開くときにデータをメモリにロードするわけで、その間CPUは遊んでいますから、一時的にCPUの負荷は下がります。当然CPUが遊んでいるというこは、処理効率が悪いということであまり好ましいことではありません。 まずは、メモリのサイズとファイルのサイズを明確にしてください。

回答No.2

ドリームホストというのはこれのことですよね。 http://www.dreamhost.com/ やっていることから考えると、SQLiteを使うと良さそうに思います。 http://wiki.dreamhost.com/SQLite メリット - CPU使用率が下がります - メモリー消費も1万5千件全部開いている現状より下がるかもしれません デメリット - ちゃんと性能を出すにはリレーショナルデータベースについて勉強しなくてはいけません - TXTファイルと違ってSQLiteを使わないと中身を読めません - TXTファイルと違ってファイルサイズは大きくなります。 PerlからSQLiteを使う方法は"Perl SQLite"で検索すると簡単に見つかります。 そのサンプルでもいじりがてら使ってみるとよいでしょう。 ...とここで終わると、「全然早くならない。遅くなった」と言われそうなので一応。 あなたがいう"照合作業"をする場合、基本的にSQLというデータベースを操作する言語を使って記述し、Perlで逐一照合するというプログラムは書きません。 例えば、NOが3のものを取り出すというのは、こんな感じで書きます。 select * from music_data where no = 3; あるいは、種類がJPOPを探す場合、こんな感じで書くかもしれません。 select * from music_data where kind = 'JPOP'; whereで書く条件はANDでつなげて複数記述できます。 select * from music_data where kind = 'JPOP' and no = 3; また、SQLでちゃんとスピードを出すにはインデックスを設定する必要があります。本の索引のようなものです。本の中で特定の言葉が使われているところを探すとき、本を最初から読んで探さず、本の最後などに付いている索引から探します。これと同じように、データベースにデータを入れた時、予め索引を作っておき、後からすぐに探せるようにします。 "照合作業"を行う項目についてはちゃんとインデックスを設定しましょう。 ...まあ、言葉は散りばめましたのであとは検索してみてください。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

@all_data=<DATA>; これは、ファイルの全部を一度読み込むので、最低でもファイルサイズと同じだけのメモリが必要です。 メモリが潤沢ならばいいのですが、状況によっては高負荷となります。 1枚目ファイルオープン→@all_data=<DATA>;→結果収集、 2枚目ファイルオープン→@all_data=<DATA>;→結果収集、 この方法では、ファイルを複数openする必要があります。 データ量自体は同じですが、「ファイルを開く」ためにディスクにアクセスするので、その分のオーバーヘッドがかかり、遅くなったり高負荷になったりする場合があります。 一行ずつ読んで処理をするのが、負荷は軽くて済みます。 速度低下による影響は少ないでしょう。 これより増えるようなら、別質問にあるように、データベースを使うのがよいと思います。 データベースは大量のデータを扱うことを目的としたもので、条件を指定して必要なものだけを受け取る、ということができるので、Perl側の負荷の軽減が期待できます。 素人にも、と言われても簡単に説明できるものではないので、サイトや参考書でデータベースについて勉強してみてください。

関連するQ&A

  • perl ファイルのデータを編集したい

    初めまして、perl をやり初めたばかりです。作業は Linux 上で行ってます。 あるテキストファイル data.txt があります。 data.txt の中は、以下のようになっているとします。 100 200 300 400 500 600 これを読み込んで、例えば、 1 2 3 4 5 6 以上の様に各数字を百分の一にして出力したいと思ってます。 一応、色々と調べながらプログラムを書いてはみましたが 思う様に出力されません。以下そのプログラム。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); $ref_x = \@x; $n_data = @x; for ($i = 0; $i< $n_data; ++$i) { $$ref_x[$i] /= 100 ; print $x[$i], " "; } print"\n"; どなたか、perl にお詳しい方教えていただけないでしょうか? 宜しくお願い申し上げます。

  • perlでのデータ処理について

    みなさんこんにちは、今、perlについてとても困っています。 以下に内容を記載しますので、わかる方がいましたら 良きアドバイスをお願いします。 #使用するファイルは2つです。 #元データ=$files1 #送信データ=$files2 #データの一行処理開始 open(IN,"$files2") || &error("$files1を開けません。"); while (<IN>) { ($no,$id,$mail,$type,$data)=split(/,/); # $files2を一行づつ読み込んで送信処理をしていきます。 . . . . . #ここからが問題点です。 # $files2を一行読み込んで送信が終わったら、$files1へ送信履歴として、 #日付を入力します。以下にスクリプトを記載しますので、良きアドバイスを #お願いします。 &get_date; @logs=(); @new=(); open(LOG,"$files1") || &error("$files1を開けません"); @logs = <LOG>; close(LOG); foreach $log (@logs){ @all_data = split(/,/,$log); if ($all_data[0] eq $id){ # $idは$files2から読み込んだ数値です。 $shori_date="$year\/$w_mon\/$w_mday"; $all_data[33]="($shori_date)($hour:$min)"; for ($i=0; $i<@all_data; $i++){ $work.="$all_data[$i],"; } chop $work; push(@new,$work); }else{ push(@new,$log); } } open(ALL,"+< $files1") || &error("$files1に書き込めません"); flock(ALL,2); truncate(ALL,0); seek(ALL,0,0); print ALL @new; close(ALL); #ここまでです。 #このようにすると、日付は入るのですが、データの更新、書き込みされたファイルを見ると #同じ内容が、2重、3重にコピーされて、ファイルに書き込みされてしまいます。 } close(IN); 以上なのですが、良きアドバイスを教えて下さい。

    • ベストアンサー
    • Perl
  • Perlプログラミングについて

    open(IN,"<○○○.txt"); open(OUT,">○○○.html");    :    処理    : というように、○○○.txtは既存のファイルで、 処理を行ったあとの出力をhtml形式にさせたいです。 ○○○.txtというのはデータベース上のファイル名から取り出してくるのを想定しています。ですので、○○○.txtは取り出された後、変数に入れるなどして、 その変数がopen(IN,"<変数");というようにしてファイルを読み込むようにしたいと考えています。 出力するファイルは固定(例えばkekka.html)にして、データベースへ要求のあったtxtファイルは処理後、すべてkekka.htmlに出力させます。 これらの処理をサーバ上ですると考えているのですが、まだまだ知識がないため、何か不備や間違いがあればご指摘いただきたいと思っています。 また、サーバの処理後、そのkekka.htmlを動的にクライアント側で表示させることは可能でしょうか。 わかりづらい質問で申し訳ありませんが、アドバイスなどよろしくお願いします。

    • ベストアンサー
    • Perl
  • Fortran:列数の分からないデータの読み込み

    列数の分からないcsvファイルを想定して、配列を用いて読み込むプログラムを作成しようと考えています。 試しに十分に大きい1次元配列を用いてデータを読みこむプログラムを作成したところ 1行目読み込み時に行をまたいでデータを読み込んでしまいました。 なんとか、各行のデータだけを読み取る方法はないでしょうか? よろしくお願いします。 ちなみにプログラムの内容、入力データ、出力結果は次の通りです。 ・プログラム implicit none integer a(5),i open(10,file='a.csv',status='old') read(10,*)(a(i),i=1,5) write(*,*)(a(i),i=1,5) close(10) ・入力データ     1,2,3,4     5,6,7,8     9,1,2,3 ・出力結果     1 2 3 4 5

  • Perlでファイルを読み込む場合のメモリの状態について

    こんにちは。 Perlでファイルを扱う場合、 open F,"./data.csv";としてオープンする場合、 オープンした段階ではまだファイルの中身はメモリに読み込まれてなくて、 例えば、一万行のファイルの場合 while (<F>) { } で五千行まできた場合、メモリには五千件まで読み込まれている。 という私の解釈なのですが、これで正しいのでしょうか?

    • ベストアンサー
    • CGI
  • perl 複数ファイルから一行ずつ読み込んで比較

    初心者向けのperl参考書がなんとか理解できる程度のperl初心者です。 一週間ほど思考錯誤してきたのですが、いくらスクリプトを書いてもどうしても自分では解決できない処理がありましたので、初めてなのですが、質問させていただきました。 二つの同じ形式の、一部情報だけ異なるファイルから一行ずつ配列を読み込んで、数値の大小を比較したいのですが・・・ ファイル構造は、下のように2行でひとつのtextデータの情報を表示する形式となってまして、 奇数行には、各textファイルの情報が、.以下の部分に4552221.2:(30.2):100、のように記載されています。 偶数行には、各テキストファイルの、IDとなる情報が、13333331のように記載されています。この奇数行と、偶数行一行ずつで、ひとつのtextデータの 情報を表しています。textというファイルは、text1から順に,text2000000まで、 2000万程度,行で言えば4000万行ほど存在しています。よって、file1もfile2も、同じ行であれば、同じtextで、同じIDのものを示しています。ずれはありません。 file1 ----------------------------- >text1. 4552221.2:(30.2):100 13333331 >text2 87999999 >text3. 3444444.1:(20.0):300 75533333 ----------------------------- 数値は意味が変わらない範囲で、比較しやすい数値に変えてあります。 この上のfile1と、下のfile2を比べたいのですが、 file2 ----------------------------- >text1. 4552221.2:(20.9):100 13333331 >text2 87999999 >text3. 3444444.1:(23.3):300 75533333 ----------------------------- 偶数行のtextファイルの欄が大事で、text名のドット(.)の後に、続けて数値が書いてある場合(上ではtext1とtext3が該当)、そのドットの後の括弧()で囲まれた中の数値の大小を比較して、 差が一定以上あるtextだけを出力するスクリプトが書きたいと思っているのですが、 これをいきなりすべてひとつのスクリプトにまとめるのは、私の知識と力量では到底無理なので、ひとつひとつ段階を踏んで処理していこうと考えました。 1、奇数行の、text.の後半に情報があるもの場合、tempファイルにその奇数行と、対になる偶数行を出力する。それを、file1、file2、個別に行う。(temp1、temp2を出力) file1で取り除かれる3、4行目のtext2は、file2でも必ず取り除かれるので、1の処理後も、file1と2の各行は、比較することが可能な状態です。 2、正規表現を使って、各行の()で囲まれた部分の最初の2桁の数字(一部は一桁の数字の場合もあり)、をtempに出力する。(temp3、temp4を出力) (この処理を行わなくても可能かもしれませんが、ややこしいので、数字だけ出すようにしました) 最後に、file1とfile2の各行の数字を一行ずつ読み込んで、数値に一定以上の差がある行の情報だけ出力したいのですが、各行を順番に分析できる方法は、while文か、配列に読み込む方法しか知りません。 前者のwhile文では、ファイルオープンは、ひたつ以上は同時には取り扱えないという情報を得たので、使えない思っています。後者の配列に読み込む方法は、桁が大きいので、実用的ではないと感じています。 二つ以上のファイルの各行の特定の数値データを、一行ずつ順に比較して、差があるものだけ抽出するにはどのようなスクリプトを書けばよいのか、ご教授下さい。 いろいろ調べましたが、(僕の調べ方が悪いと思いますが)適切なコマンドや方法にたどり着けません。 試してみた方法 ファイルハンドルを二つ指定して、while文の条件中に、andで条件を二つ指定してファイルハンドルから読み込んでやればよいと思ったのですが、実行するとエラーになってしまいます。ググっていろいろ調べてみたところ、ファイルハンドルの二つ指定はできないとの記述を見つけたので、whileの条件に複数のファイルハンドルを記述するこの方法はあきらめて、ここで、ストップしています。 まわりに、perlを扱える方がいらっしゃれば質問に伺うのですが。もしよろしければ、簡単でもご教授いただけますと幸いです。宜しくお願い申し上げます。

    • ベストアンサー
    • Perl
  • Perlのプログラミングについて

    Perlのプログラミングでつまづきました。 # ファイルから指定文字列を含む行を収集する # 入力ファイルのオープンと読み込み print( "入力ファイル名?" ); $n = <STDIN>; chomp( $n ); open( FIN, "<$n" ) or die "入力ファイルオープンエラー: $!\n"; $n = @a = <FIN>; close( FIN ); print( "$n 行読み込みました\n" ); # 行の収集 print( "検索文字列?" ); $x = <STDIN>; chomp( $x ); $ptn = $x; #指定の文字列 $x = @b = grep( /$ptn/, @a ); print( "$x 行見つかりました\n" ); # 出力ファイルのオープンと書き出し print( "出力ファイル名?" ); $y = <STDIN>; chomp( $y ); open( FOUT, ">$y" ) or die "出力ファイルオープンエラー: $!\n"; print FOUT ( $ptn, "\n" ); print FOUT ( $x, "\n" ); print FOUT ( @b ); close( FOUT ); というプログラムで実行すると C:\My Perl\pl>perl プログラムの実行.pl 入力ファイル名?sample1.txt 168 行読み込みました 検索文字列?k 45 行見つかりました 出力ファイル名?out3-24.txt 続行するには何かキーを押してください . . . となり出力ファイルの中身が表示されません。 どこを間違えているのかご指摘いただけないでしょうか?

  • perlでの別ファイルへの出力について

    perlでファイルAから読み出した値を別ファイルBに出力させたいです。 イメージとしては -------------------------------- open(FILE,ファイルA); while(<FILE>){ my $line = "$_"; system("ls -l $line"); #←ここの結果を1行ずつファイルBに出力したい } close(FILE) --------------------------------- 上記の場合どのように記述すれば良いのでしょうか? bashでは簡単にかけるのですが、 業務上perlを使用する必要がある為こまっております…。

    • ベストアンサー
    • Perl
  • PerlでFILEを埋め込もうとするとエラー

    Perlでアクセスカウンターを作ろうと思っています。 そこでファイルオープンを勉強し、 CGIプログラムを実行しようとしたところ、 エラーが起こりました。↓ Internal Server Error The server encountered an internal error or misconfiguration and was unable to complete your request. Please contact the server administrator, ********@*********(伏せてあります) and inform them of the time the error occurred, and anything you might have done that may have caused the error. More information about this error may be available in the server error log. ------------------------------------------ Apache/2.0.55 (Win32) Server at 127.0.0.1 Port 80 ソースを見てもおかしい所は見当たりません…↓ #! c:/perl/bin/perl open(FILE, "./sample.txt"); @data = <FILE>; close (FILE); print <<END; Content-type: text/html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <title>sample</title> </head> <body> <p>$data[0]</p> <p>$data[1]</p> <p>$data[2]</p> </body> </html> END サーバーはApacheを使っています。 原因がわかったら教えてください。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • 効率の良いデータ照合のさせ方

    2つのCSVファイル(どちらもデータ件数が1000件を超える)を照合して SQL文の発行の有無を処理するプログラムを組んでいます。↓ open(ファイル1, ファイル1の場所) || die("$!"); while(<ファイル1>){ chomp($_); @data_1 = split(/,/, $_); open(ファイル2, ファイル2の場所) || die("$!"); while(<ファイル2>){ chomp($_); @data_2 = split(/,/, $_);   # ここでファイル1の指定した列のデータとファイル2の指定した列のデータ照合しています。↓   # ($data_1[列]、$data_2[列]) if(($data_1[0] == $data_2[5]) and ($data_1[1] == $data_2[3]) and ($data_1[3] == $data_2[4]) and ($data_1[4] == $data_2[0])){ #insert文     #update文 } } } 上記のような組み方をすると、やはり実行速度がかなり遅くなりました。 8分ぐらい処理にかかってしまいました; 効率的な処理のさせ方ということで、関数などを調べているのですが、 これという関数も見つからず困っています。 プログラムの組み方自体に問題があるとは思うのですが・・ なにぶん、経験が浅いというのもあり・・・; 何か良い方法をご存知の方、ご指導お願いします。

    • ベストアンサー
    • Perl

専門家に質問してみよう