昔ながらの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を最小限の変更で動作させられるかどうか…