日付をDBに入れる時にアプリケーション側でやるか、DB側でやるかって話(ベンチマーク)

PostgreSQLには今の日付を入れるcurrent_dateなんてものがあることを今更知った。
今まではPerlでTime::Pieceとかを使って先に日付を用意して、SQL文に入れてたんだけど、どっちが速いのか気になったので計測してみた。

注意(2010/10/19追記)

id:perlcodesampleさんの指摘で計測による結論が正確ではないと分かったのでこのエントリは参考にしないで下さい。


とりあえず環境。Ubuntu10.10(i386)とそこそこ新しいPC。
PerlとPostgeSQLはapt-getを使って入れた。

Polaroidoon@ubuntu:~/perltest$ perl -v

This is perl, v5.10.1 (*) built for i686-linux-gnu-thread-multi
(with 40 registered patches, see perl -V for more detail)

Copyright 1987-2009, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

Polaroidoon@ubuntu:~/perltest$ psql --version
psql (PostgreSQL) 8.4.5
contains support for command-line editing


んで、テーブル。

test=> \d datebench
          Table "public.datebench"
 Column |          Type          | Modifiers
--------+------------------------+-----------
 date   | date                   | not null
 time   | time without time zone | not null

あとはテストに使ったプログラム。

#!/usr/bin/perl

use warnings;
use strict;
use Benchmark qw/timethese cmpthese/;
use DBIx::Simple;
use Time::Piece;

my @dsn = (
        'dbi:Pg:host=localhost;database=test;',
        'username',
        'password',
        {RaiseError => 1},
);

my $t;

my $db = DBIx::Simple->connect(@dsn)
        or die DBIx::Simple->error;

my $result = timethese(10000, {
        name1 => sub {
                $t = Time::Piece::localtime();

                $db->query(
                        'INSERT INTO datebench (date,time) VALUES (?, ?);',
                        $t->ymd,
                        $t->hms);
        },
        name2 => sub {
                $db->query(
                        'INSERT INTO datebench (date,time) VALUES (current_date, current_time);'
                        );
        },
});

cmpthese($result);


CPANのBenckmarkモジュールを使って1万回実行した結果で測定。
Benckmarkでの結果にはIO待ちの時間が出なくてCPU時間だけが出るらしいんだけど、まぁ、テーブルに書き込む内容は同じようなモンでしょ。と逃げる。


そして、実行結果がこれ。

Polaroidoon@ubuntu:~/perltest$ perl test.pl
Benchmark: timing 10000 iterations of name1, name2...
     name1: 85 wallclock secs ( 4.84 usr +  0.78 sys =  5.62 CPU) @ 1779.36/s (n=10000)
     name2: 84 wallclock secs ( 1.73 usr +  0.22 sys =  1.95 CPU) @ 5128.21/s (n=10000)
        Rate name1 name2
name1 1779/s    --  -65%
name2 5128/s  188%    --

name1がTime::Piece。
name2がPostgeSQLまかせ。

ということでSQL文で用意した方がいいみたい。
次からこっちにしよう。
(2010/10/19削除)

追記(2010/10/19追記)

perlcodesampleさんに教えていただいたwallclock secsで比較すると85secと84sec。
ということはほぼ一緒だなぁ。DBとPerlのCPU使用率とかもっと他のものまで見ないと比較は難しそうだ。


Benckmark参考:
http://d.hatena.ne.jp/perlcodesample/20100509/1276960096