読者です 読者をやめる 読者になる 読者になる

アルパカDiary Pro

はてなブログProではありません

Postgresql システム時刻取得関数について発見

データベース Postgres

バッチ処理pl/pgsqlも使ってたりするんですが、
先週たまたまアボートしてログ見てる時に気付いたことが。


あれ、開始と終了の時刻が一緒。


ログ出力で、ストアドの開始と終了に実行日付出してるんですが、
どのストアドみても開始と終了の時刻が一緒になってるんです。
なんで?バグ?


と思って、ドキュメント見直したら仕様でした!
時刻取得にnow()を使ってたんですが、トランザクション内で常に同じ値を返すらしい。

now()はCURRENT_TIMESTAMPと同じもので、伝統的なPostgreSQL関数です。 transaction_timestamp()はCURRENT_TIMESTAMP同様のものですが、明確に何が返されるかを示す名前になっています。 statement_timestamp()は現在の文の実行開始時刻を返すものです(より具体的にいうと、直前のコマンドメッセージをクライアントから受け取った時刻です)。 statement_timestamp()およびtransaction_timestamp()はトランザクションの最初のコマンドでは同じ値を返しますが、その後に引き続くコマンドでは異なる可能性があります。 clock_timestamp()は実際の現在時刻を返しますので、その値は単一のSQLコマンドであっても異なります。

PostgreSQL日本語ドキュメント 9.9. 日付/時刻関数と演算子


なるほどー。トランザクション内で使う場合は
用途で使い分ける必要があるわけですね。
試してみた。

トランザクションなし

postgres=# select now();
              now
-------------------------------
 2009-02-21 23:34:48.343367+09
(1 row)

postgres=# select now();
             now
------------------------------
 2009-02-21 23:34:50.44536+09
(1 row)

普通に現在時刻を返す。

トランザクション設定 -> now(), current_timestamp, transaction_timestamp()

postgres=# begin;
BEGIN
postgres=# select now();
              now
-------------------------------
 2009-02-21 23:35:00.143057+09
(1 row)

postgres=# select now();
              now
-------------------------------
 2009-02-21 23:35:00.143057+09
(1 row)

postgres=# select current_timestamp;
              now
-------------------------------
 2009-02-21 23:35:00.143057+09
(1 row)

postgres=# select transaction_timestamp();
     transaction_timestamp
-------------------------------
 2009-02-21 23:35:00.143057+09
(1 row)

何度実行しても結果は一緒。

トランザクション設定 -> statement_timestamp(), clock_timestamp();

postgres=# select now();
              now
-------------------------------
 2009-02-21 23:35:00.143057+09
(1 row)

postgres=# select statement_timestamp();
     statement_timestamp
------------------------------
 2009-02-21 23:35:39.90937+09
(1 row)

postgres=# select statement_timestamp();
      statement_timestamp
-------------------------------
 2009-02-21 23:35:45.633752+09
(1 row)

postgres=# select clock_timestamp();
        clock_timestamp
-------------------------------
 2009-02-21 23:35:52.520483+09
(1 row)

トランザクション内でも、その時点の時刻を取得。


どれを使ったらいいかはよくわからんので、
とりあえず名前だけで clock_timestamp() に決めました。
全部のストアド置き換えなきゃ…


※ちなみに今回はPostgres8.3.5で試してみましたが、
 Postgres8.1.xだとstatement_timestamp()やclock_timestamp()が存在しないっぽい…
 旧バージョンではどのような代替手段があるんだろう?