月別アーカイブ: 2013年3月

PerlからMySQLを操作してみる

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