• ベストアンサー
  • 困ってます

DBMとハッシュ

参考書を読んだ所、dbmデータベースは データの検索・削除等を行う場合に速くて良いとありました。 ここで質問なのですが、データベースのデータを変更せず データの参照のみを必要とする場合、 外部ファイル化して同じ効果を得られる別の方法… 例えば、ハッシュ配列をそのままdb.txtに保存して require 'db.txt'; としてみたり、 sub OKWeb { $OKWeb{'123'} = 'あいう';       ~ return $OKWeb{$_[0]}; } としてみたりといった方法と比べても速いのでしょうか。 また上記の方法以外にもっと速くデータを参照できる方法がありましたら教えて下さい。

共感・応援の気持ちを伝えよう!

  • 回答数2
  • 閲覧数290
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • 回答No.1

データのサイズや参照の仕方によるのではないでしょうか。 比較的小さなデータから1レコード取り出すようなときは、 大抵の場合ハッシュでも充分かと思います。場合によっては *DBM_Fileよりも高速でしょう。 ただ、ハッシュの式を外部ファイルにしろサブルーチンにしろ 埋め込んでおいて読ませる場合、Perlがその文を解釈、評価する 時間が掛かることにご注意ください。つまりあまりデータがでかいと、 いつまでたってもそのファイルをがらがら読んでて終わらないよ、 ということもあり得るわけです。もちろんすべてを読みこむのに 必要なメモリも消費しますね。 読みこんだあと全部ソートしたいとか集計したいとかの 目的があるならメモリに読みこむ必要があるでしょうが、 たくさん読みこんだ挙句に参照するデータはひとつ二つだけ…といった ことになるのだったら、*DBM_Fileなどを利用して外部ファイルに置いて おいて、必要な部分だけ読みに行く方が有効でしょう。 他に、検索がより複雑になるのだったらRDBMSなどにお任せしたほうが 楽でしょうし、逆にデータが必ず順番に並んでいてサイズも固定長 にしておけば読みこむべき場所が「データ番号 * データサイズ」で一発 でseekできるから速い、なんてテクニックが使える状況もあるでしょう。 あるいはひとつひとつ検索するのを10回繰り返すより、 ひとつ検索したあとはそこから続けて10レコード分まとめて 読みこんじゃえばいい、というような構造のファイルを作れるとか。 (まあ実際、*DBM_Fileの中には上記のようなテクニックを使っている ものもあると思います。多くの人が改良し合ったコードの方が効率が 良いでしょうから、もし自前のものを書くおつもりならその前にいろいろと 調査されることをお薦めします) というわけで、速いかどうかは、データの構造ややることによる、と お答えします。月並みで申しわけありません。 なお、SDBM_Fileなどはファイルサイズの制限があったりします。 perldoc AnyDBM_Fileなどをご覧ください。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

詳しく、丁寧なご回答ありがとうございました。 疑問が解決しました! 本当はポイントを全部つけたかったのですが 同一人物へのポイントは駄目なんですね。すいません。 ありがとうございました。

その他の回答 (1)

  • 回答No.2

おわかりのことでしょうが老婆心ながら補足します。 ハッシュは優れたデータ格納方法ですが、作成時には各キーの ハッシュ値を計算して、対応するバケットにデータを突っ込んでおく、 またPerlの場合要素数がある程度増えると自動的にバケットの数を 増やす仕組みになってますけど、そういったもろもろの処理の時間が、 わずかながらでも掛かっていることにご注意ください。 DBファイルの場合その作成時にこれらの処理をまとめて行っておく (インデックスを張るような場合)と考えると、数百件のデータを 頻繁に呼び出すようなときはやっぱりDBを使うか、データ形式に 特化した格納方法を使う方が有利です。 また、例としてお書きになったサブルーチンを使うほうは、呼び出すたびに 毎回代入し、ハッシュ作成を行うので、データが少ない間ならばいいですが多くなる ほどとても遅くなるでしょう(一度しかそのサブルーチンを呼ばない ならまた話は別です)。 あと、「全部ソートしたいとか集計したいとかの目的があるなら メモリに読みこむ必要がある」と書きましたが、集計する場合は 1レコード読んでは集計して、そのレコードを廃棄して次のレコード を読みこめばいいですね。メモリの節約にもなります。 [蛇足] よく初心者の方のプログラムで見かけるのが my @data = <DATA>; でファイルを丸ごと読んでしまう方法ですが、これはファイル が小さいうちはいいでしょうけど、大きくなるとその分メモリを 消費するわけですから、あまり望ましいとはいえません。 (カウンタのCGIサンプルから来てるのかな?なぜみな一様にこんな 書き方をするのか不思議です) while (<DATA>) { } で1行ずつ処理すべきです。多少早ければメモリなんか…という 気持ちもわかりますが、あまりメモリ消費量が多くなればOSが メモリのスワップアウトでがらがらとディスクの読み書きを始め、 全体が極端に重くなるでしょう。メモリ消費も少ないのに越したことは ありません。 本題からはずれてしまいました。すいません。

共感・感謝の気持ちを伝えよう!

関連するQ&A

  • DBMのことで・・・

    現在DBMを用いて簡単なデータベースを作成しています。 どこぞのCGIゲームのように、リアルタイムにデーターベースの内容が書き換えられる(戦闘をすればお金がプラス等)ようにしたいのですが、うまくいきませんorz #!/usr/bin/perl use AnyDBM_File; use Fcntl; print "Content-type: text/html\n\n"; dbmopen(%DBM, 'id', 0666); $DBM{"baka"} = ("0<>1<>2<>"); dbmclose(%DBM); print<<"HTMLTAG"; DBを作成しました HTMLTAG tie %DBM,AnyDBM_File,"id",O_RDONLY,0666; @aaa = split(/<>/,$DBM{"baka"}); untie %DBM; print"$aaa[0]"; $aaa[0]++; とりあえずこのスクリプトで、ブラウザの更新をおすたびに表示される数字が1あがっていく(プラスされて書き換えられる)ようにしたいのですが・・・ 多分ですがゲーム等の場合、いちいちdbmopenで書き換えてないとおもうので、その方法を知りたいというわけです。 いちおうこの段階ではDB作成、DBの読み込みと表示はできています。 ご教授おねがいします。

  • DBMとテキストファイルのどちらが良いと思われますか?

    こんにちは、 windows + ActivePerl の環境で、 簡単なデータを記録して後から検索、修正、削除したいのですが、 データを格納するのに、テキストファイルにするか、DBMを使用するか 悩んでいます。 テキストファイルに、(行番号,"*" x 100)のレコードを10万行出力したら、約10MBで、 DBMファイルに (行番号=>"*" x 100)のハッシュを出力したpagファイルは510MBでした。 その後、99999番目のレコードを以下のスクリプトで表示したところ、 体感的には違いがありませんでした。(どちらも一瞬で終了します) ******************************* #テキストファイル 検索 my $id = 99999; my $data; open(FILE,"<TEXTfile.txt") or die ; while(my $line = <FILE>){ if($line =~ /$id/){ $data = $line; last; } close FILE; print $data; ******************************* #DBMファイル 検索 my %DBM = (); my $id = 99999; my $data; dbmopen(%DBM,"DBMfile",0666) or die; if (defined $DBM{$id}){ $data = $DBM{$id}; } dbmclose %DBM; print $data; DBMを使用した場合、すべてのデータをメモリ上に展開するのでしょうか? もしそうなら、510MBも消費されてはたまりませんので、テキストファイルになりますが、 コーディング等はDBMの方が楽かな?と考えています。 データベースを利用できない環境の場合、どちらが良いのでしょうか? ご意見お願いします。

    • ベストアンサー
    • Perl
  • DBMについて教えてください

    最近切り替えたレンタルサーバーのサポートページで始めてDBMという言葉を知りました。 簡易的なデータベースライブラリ(そもそも、このライブラリという意味もよく・・)なのかな?となんとなく想像してるのですが、実際にどれくらいの規模のものなのか、まったく手がかりがつかめないでいます。 いろいろ検索してまわったのですが、実用するにはどうすればいい、そもそもこういうものである、などの入門の入門的なドキュメントは発見できずじまいでした。 これをうまくcgiで使うと、もしかして、データの管理(例えば、投稿してもらった小説などでも)が凄く簡潔になるのでは!?未知の世界が待っているのでは!?と実体を知らないだけに、どんどん幸せな事ばかり想像してしまっています。。(^^; どうか、DBMについてわかりやすいご説明(もしくは参考になるサイト)、こんな事ができるよ、など教えていただけないでしょうか! もう、気になって気になって・・・ よろしくお願いします。 補足: 現在のわたしの知識は、 .linux→MACにインストールしてちらっと触った程度  ・Perl→既存の掲示板などのcgiに機能をちょっとカスタマイズする程度 です。 レンタルサーバーのHPには、DBMはGDBM_File・DB_File・ SDBM_File・NDBM_Fileのどれかを使ってください、といった内容がかかれていました。

    • ベストアンサー
    • CGI
  • ハッシュのリファレンスを用いた処理

    ActivePerl 5.8 , WinXP SP2の環境です。 Perl スクリプトを用い、ファイルから複数のブロックからなる情報をよみとり、個別のハッシュを作り、それをリファレンスの配列としてまとめて後から参照するという操作をしたいのですが、詰まってしまいました。。 例として読み取るファイルは ---input.txt--------- >1 Jan 1 Feb 4 >2 Mar 9 Apr 3 >3 Oct 8 Nov 4 ------------------ ここから1,2,3の個別のハッシュ {Jan => 1 Feb => 4} {Mar=> 9 Apr =>3} {Oct =>8 Nov =>4} を作成し、それぞれのハッシュのリファレンスの配列をつくり、その後からすべてのハッシュの中身を個別に出力させたいと思いました。 次のようなスクリプトを作成したのですが思ったように作動しません。 use strict; open (IN, "input.txt") or die ("cant open file \n"); my $reff; my @array_of_reff; my %hash; my $count = 0; while(<IN>){ my $line = $_; ######ここでは各ブロックの頭の ">"を認識し、2個目以降であれば直前までで作ったハッシュのリファレンス($reff)を配列@array_of_reffに入れる。 if($line =~ /^>/){ if($count >0){ $reff = \%hash ; push (@array_of_reff, $reff); %hash = (); } $count++; } ########ここではアルファベットが入った行を認識して、ハッシュに追加しています if($line =~ /^[A-Za-z]/){           $line =~ /([A-Za-z]+)\s+/; my $month = $1; $line =~ /\s+(\d+)/; my $day= $1; $hash{$month} = $day;     } ###ここはファイルの最後になったら直前まで作っていたハッシュののリファレンス($reff)を配列@array_of_reffに入れる。 if( eof ){ $reff = \%hash ; push (@array_of_reff, $reff); } } #####ハッシュのリファレンスの配列(@array_of_reff)からもとのハッシュを参照し、ハッシュごとに出力 foreach my $reff_of_hash (@array_of_reff){    print "output";    while( (my $key,my $value) = each %$reff_of_hash ){     print "\n" , $key, " : ", $value, ;    } } このスクリプトを実行すると Nov 4 Oct 8 という3つめのハッシュのなかみが3回出力されてしまいます。自分では3つの別のハッシュをつくっているつもりでも、どうやら1種類しか作れていない、もしくはハッシュが上書きされているようなのですが、原因がわかりません。 この例だけ見るとハッシュのリファレンスを使う必要はないのですが、実際にはもうすこし大きいスクリプトで"ハッシュのリファレンスの配列を他のサブルーチンに渡す"ということを想定しており、これが解決できず先に進めない状態です。 アドバイス、解決法がわかったら教えていただけないでしょうか。

    • ベストアンサー
    • Perl
  • Perlのサブルーチンで連想配列(ハッシュ)を渡す

    Perlのサブルーチンで連想配列(ハッシュ)を渡す方法 -------------------------------------- $str=rep::replace(%A,$B,@C); -------------------------------------- sub refidrep ( \%\$\@ ){ my(%A,$B,@C)=(@_); } -------------------------------------- では、上手くいきませんでした。 どのようにしたら、連想配列をサブルーチンに渡せるのでしょうか? 分かる方いらっしゃいましたらご教授ください。

    • ベストアンサー
    • Perl
  • Perlのサブルーチンの引数に配列やハッシュをCall by Valueすることはできない?

     タイトルどおりなんですが・・・。  Perlのサブルーチンに配列やハッシュを実体渡ししようとしたんですが,どうやってもできません.あきらめて,参照渡しにしたら,なんかうまくいっている模様です.  これは,そもそも,はじめから参照渡ししか用意されていない、ということでしょうか?.それとも,何か実体渡しする方法があるのでしょうか?.  後,余談なんですが,配列やハッシュの要素に別の配列やハッシュの実体を入れることはできるのですか?.これもちょっと試してみたらできなさそうだったのですが,あちこちのWebにある入門マニュアルみたいなページを見ても,その辺の話が「できる」とも「できない」ともほとんどの場合かいてなくて,自分の試し方が悪いのか,それとも無駄なことを延々とやっているのかがわからなくて疲れます.

  • Perlは戻り値で、ハッシュや配列を正しく返さないのでしょうか?

    Perlは戻り値で、ハッシュや配列を正しく返さないのでしょうか? 返せるように見えて実際は、歯抜けのデータなど、不安定で使い物になりません。 よって、リファレンスでスカラー値で利用するのが正論でしょうか? $a = ''; %b = (); @c = (); ○ return ($a, \$b, \$c); × retuen ($a, %b, @c); ○ my ($a, $b, $c) = aru_kansuu($hikkey, ('komori')); × my ($a, %b, @c) = aru_kansuu($hikkey, ('komori'));

    • ベストアンサー
    • Perl
  • dBmとdBμVの変換について

    初歩的な質問で申し訳ありません。 数学が苦手なので皆さんの知識を拝借したいと思っています。 電力比を電圧比に変換する計算方法を教えてください。 たとえば -100dBmはインピーダンス50Ωとした場合何dBμVになるのでしょうか? スペアナで測定したデータをエクセルでグラフを作りたいのですが設定の仕方が悪いのかよくわかりませんが、DATAファイルはUNITをdBμVにしても電力比のデータでしか保存されていません。 画面上の表示、及び画像で保存したデータはきちんと表示されています。 よろしくお願いします。

  • フォームデータをハッシュで返すには?

    前画面の入力内容を&ReadParse()を用いて取得し、 その後テキストボックス名などのオブジェクト名と 入力内容をEUCに変換してハッシュで返すという サブルーチンを作っています。 サブルーチンなので不特定多数の画面から呼び出されます。 下記のとおりにしてみたのですが、うまくハッシュに入っていないらしく、値を取得することができません。 どのようにすればいいでしょうか? ----以下プログラム---- sub Comp_SetParam { &ReadParse(*form); # パラメータ受取 #引数として渡されたフォームデータを格納 while(($key,$val) = each(%form)){  #キー名(画面のオブジェクト名)をEUC変換  &jcode::convert(*key ,'euc');  #画面入力値をEUC変換  &jcode::convert(*val ,'euc');  %in = ("$key" => "$val"); } #ハッシュにし返す  return %in; }

    • ベストアンサー
    • Perl
  • 配列やハッシュで中身が同じか簡単に調べることは可能でしょうか?

    スカラ型なら my $a = "a"; my $b = "b"; if( $a eq $b)の用に比較が簡単に出来ますが、 配列やハッシュはどのように中身が同じかどうか調べることは可能でしょうか? 配列でも複雑な(例えば配列のデータがハッシュ値)のような以下の ものを中身が同じが比較する方法です。 固定でなく、どんなデータが入ってきても数やキーが異なっても比較する方法が知りたいです。 my @ary1 = (); $ary[0]{'test_a'} = "a"; $ary[0]{'test_b'} = "b"; $ary[1]{'test_a'} = "aa"; $ary[1]{'test_b'} = "bb"; my @ary2 = (); $ary[0]{'test_a'} = "aa"; $ary[0]{'test_b'} = "bb"; $ary[1]{'test_a'} = "aaa"; $ary[1]{'test_b'} = "bbb";

    • ベストアンサー
    • Perl