• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:DBMとハッシュ)

DBMとハッシュ

このQ&Aのポイント
  • dbmデータベースを使用すると、データの検索・削除が速く行えます。
  • データの参照のみを必要とする場合、ハッシュ配列を外部ファイル化して保存する方法もあります。
  • 他にも高速なデータの参照方法が存在する場合、教えてください。

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

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

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

ryogoku
質問者

お礼

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

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (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
  • Perlのサブルーチンの引数に配列やハッシュをCall by Valueすることはできない?

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

  • ハッシュのリファレンスを用いた処理

    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
  • ハッシュの中身の表示

    ハッシュの中身の確認ができなくて困っています。 下記のような実行文においてです。 当然、test の戻り値は、スカラーとハッシュです。ハッシュを戻すときには参照渡し記号の\もつけています。 my ($return_code, %hash_data) = test(); 表示しようとすると、 Hash(0x5b04) のような表示にしかなりません、、 (試した表示方法は、下記4つです。) (環境は、WindowsXP上での、ActivePerl-5.10.0.1004 です。) foreach $key ( keys( %Hash ) ) { print "キー値 : $key\n"; print "値 : $Hash{$key} \n " } while ( ( $key , $value ) = each %Hash ){ print "キー値 : $key\n"; print "値 : $value \n " ; } use Data::Dump qw(dump); print dump(\%hash); #print %display_test; 宜しくお願いします。

    • ベストアンサー
    • Perl
  • C++ではハッシュはどのように書けばよいのでしょうか?

    配列はできることがわかりましたが、ハッシュは、C++ではどのように記述ふれば良いのでしょうか? /* C++ VS2005でハッシュのようなことは可能でしょうか? */ int main(void){ /* Perlの場合 %ken = ( "北海道"=>"札幌市", "宮城県"=>"仙台市", "東京都"=>"東京(新宿区)", "愛知県"=>"名古屋市", "大阪府"=>"大阪市", "広島県"=>"広島市", "福岡県"=>"福岡市", "沖縄県"=>"那覇市", ); print $ken{"東京都"}; */ return 0; }

  • 『ハッシュ値のみ送信』…?

    VirusBusterCloudの解説が提供されている某ページ(http://ascii.jp/elem/000/000/552/552139/index-2.html)を閲覧しますと、次の記述が見付かります。 >それら機能でもウイルスかどうかの判定ができないファイルを見つけた場合は、クラウド上にあるデータベースを参照します。クラウドにクエリをかける際にはハッシュ値のみ送信し、ネットワークトラフィックを圧迫しない工夫もしています。また、多く出回っているウイルスのシグネチャはパソコン側に保存する仕組みも、クラウド側へのクリエを減らすことに役立っています。 でも、此の文章の中で『ハッシュ値のみ送信』という旨の箇所の意味が分からないものですから、仕組みを教えて頂けませんでしょうか? 非常に御恥ずかしいことなのですが、宜しく御願い申し上げます。

  • dBmとdBμVの変換について

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

  • 配列やハッシュで中身が同じか簡単に調べることは可能でしょうか?

    スカラ型なら 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