dbicでバルクインサート

1個のデータを作るcreateを100回するより、100個のデータを作るcreateを1回の方が早い。
これをバルクインサートと言う、と。
んでdbicでやるわけで。

    for (1..100) {
        my $length = int(rand(20)) + 1;
        my $str = String::Random->new->randpattern('.' x $length);
#    ふつーにいったらこーなるわけだ
#       $c->model('DBIC::Word')->create({word => $str});
        push @word_in,{id => $_, word => $str, created_at => $now};
    }
    $c->model('DBIC::Word')->populate(\@word_in);

で、メソッドの中でこういうことをするわけだけど、最後の行にpopulateを書いてはいけない。
perlではブロックの最終行が戻り値になる。んでpopulateはアレイで評価されるので、最後の行に書いてしまうと100回のinsert文が実行される。

900回のinsertを走らせて、ふつーの場合とバルクインサートでの比較をば

ふつー
.----------------------------------------------------------------+-----------.
| Action                                                         | Time      |
+----------------------------------------------------------------+-----------+
| /auto                                                          | 0.006055s |
| /create_dummy                                                  | 3.383838s |
| /end                                                           | 0.093589s |
|  -> /render                                                    | 0.092346s |
|   -> xxx::View::TT->process                                    | 0.087332s |
'----------------------------------------------------------------+-----------'
 
 
バルクインサート
.----------------------------------------------------------------+-----------.
| Action                                                         | Time      |
+----------------------------------------------------------------+-----------+
| /auto                                                          | 0.006350s |
| /create_dummy                                                  | 0.324708s |
| /end                                                           | 0.091025s |
|  -> /render                                                    | 0.090256s |
|   -> xxx::View::TT->process                                    | 0.087133s |
'----------------------------------------------------------------+-----------'


実に10分の1の時間で済んだ。


で、不思議なことにdatetimeオブジェクトをつっこんだらpopulateが効かない。

    my $now = '2008-11-28 21:58:48';
    #my $now = DateTime->now( time_zone => $time_zone );


上の場合はバルクインサートが行われ、下の場合はふつーのinsertになってしまった。
何故だ?これじゃ使い物にならん。