昔ながらのPerl/CGIではデータをテキストファイルに保存しているわけだが、データの肥大化が原因なのか、動作が遅くなってきた。
その対策として、データをスリムアップするとか処理を効率化するとかが考えられるが、この際モダンな感じでデータの保存をMySQLに保以降してみてはどうだろうかと思った。
目標
- 昔ながらの「<>」区切りテキスト(UTF-8)を自動でMySQLに保存する(これまでのデータの移行)
- MySQLに保存されたデータを取り出す
- MySQLのデータを更新する(今回は行わない)
準備
MySQLにデータベース「mysqltest」をutf8_general_ciで作成。一般ユーザID:test、pass:testpassで利用できるように設定。
テスト用に小規模なデータを作成。掲示板のログファイルを想定。
形式は
通し番号<>名前<>書き込み内容
とする。
bbsdata.txt
1<>名無し<>てすと 2<>ななーし<>てすとー 3<>anonimous<>test
スクリプトを作成
ちょっと遠回しなスクリプトだけど、気にしない。
mysqltest.pl(データ移行)
use DBI; my $mysqldb = 'DBI:mysql:mysqltest'; my $mysqluser = 'test'; my $mysqlpass = 'testpass'; my $data = 'bbsdata'; my $datafile = "./$data.txt"; my @dataarray = ('no','name','content'); my @datatypearray = ('int','text','text'); my @filedata; open(DATA,"$datafile") || die("error:$datafile"); chomp(@filedata=<DATA>); close(DATA); my @datalist; foreach(@filedata){ my @tmp = split(/<>/, $_); my %data; foreach(@dataarray){ $data{$_} = shift(@tmp); } push(@datalist,\%data); } my $dbh = DBI->connect($mysqldb,$mysqluser,$mysqlpass); my @sql; $sql[0] = "create table $data ("; my $fields; my @values; for(my $i=0; $i <= $#dataarray; $i++ ){ $sql[0] .= "$dataarray[$i] $datatypearray[$i]"; $fields .= $dataarray[$i]; if($i == $#dataarray){ $sql[0] .= ');'; }else{ $sql[0] .= ', '; $fields .= ','; } } for(my $j=0; $j <= $#datalist; $j++ ){ my $tmp; for(my $i=0; $i <= $#dataarray; $i++ ){ if($datatypearray[$i] eq 'text'){ $tmp .= $dbh->quote($datalist[$j]->{$dataarray[$i]}); }else{ $tmp .= $datalist[$j]->{$dataarray[$i]}; } if($i == $#dataarray){ }else{ $tmp .= ','; } } $sql[1+$j] = "insert into $data ($fields) values ($tmp);"; } print "$fields\n"; print "$sql[0]\n"; print "$sql[1]\n"; print "$sql[2]\n"; foreach(@sql){ my $sth = $dbh->prepare($_); $sth->execute; $sth->finish; } $dbh->disconnect;
mysqltest2.pl(データ読込)
use DBI; my $mysqldb = 'DBI:mysql:mysqltest'; my $mysqluser = 'test'; my $mysqlpass = 'testpass'; my $data = 'bbsdata'; my @dataarray = ('no','name','content'); my $dbh = DBI->connect($mysqldb,$mysqluser,$mysqlpass); my $sql = "select * from $data;"; my $sth = $dbh->prepare($sql); $sth->execute; while(my $ref = $sth->fetchrow_hashref){ foreach(@dataarray){ print "$_ = $ref->{$_},"; } print "\n"; } $sth->finish; $dbh->disconnect;
実行結果
# perl mysqltest.pl no,name,content create table bbsdata (no int, name text, content text); insert into bbsdata (no,name,content) values (1,"名無し","てすと"); insert into bbsdata (no,name,content) values (2,"ななーし","てすとー"); # perl mysqltest2.pl no,name,content select * from bbsdata no = 1,name = 名無し,content = てすと, no = 2,name = ななーし,content = てすとー, no = 3,name = anonimous,content = test,
課題
とりあえずここまではうまくいった。
あとは実際のCGIを最小限の変更で動作させられるかどうか…