技術・開発

PostgreSQLのnow()は現在時刻ではない

2015年9月25日

Postgresを使用したバッチにて、処理終了時に終了日時を挿入するバッチを作成したのですが、処理時間が長いバッチでも終了日時が正しく入力されていなかったので調べてみました。

now()は現在時刻を取得するわけではない

Postgresのドキュメントに記載されていました。

PostgreSQLは、現在の日付時刻に関した値を返す多くの関数を提供します。
下記の標準SQL関数は現在のトランザクションの開始時刻に基づいた値を返します。

  • CURRENT_DATE
  • CURRENT_TIME
  • CURRENT_TIMESTAMP
  • CURRENT_TIME(precision)
  • CURRENT_TIMESTAMP(precision)
  • LOCALTIME
  • LOCALTIMESTAMP
  • LOCALTIME(precision)
  • LOCALTIMESTAMP(precision)

PostgreSQLのnow()はtransaction_timestamp()と同じになります。
そのため、トランザクション内でnow()を実行した場合はトランザクション開始日時が返却されます。

例)左がnow()の結果 右が現在時刻を取得するclock_timestamp()の結果

postgres=# select now(),clock_timestamp();
now                            | clock_timestamp
-------------------------------+-------------------------------
2015-09-25 00:26:05.476531+09  | 2015-09-25 00:26:05.476616+09
(1 row)

postgres=# begin;
BEGIN
postgres=# select now(),clock_timestamp();
now                            | clock_timestamp
-------------------------------+-------------------------------
2015-09-25 00:26:09.436512+09  | 2015-09-25 00:26:10.605541+09
(1 row)

postgres=# select now(),clock_timestamp();
now                            | clock_timestamp
-------------------------------+-------------------------------
2015-09-25 00:26:09.436512+09  | 2015-09-25 00:26:19.564585+09
(1 row)

postgres=# commit;
COMMIT
postgres=# begin;
BEGIN
postgres=# select now(),clock_timestamp();
now                            | clock_timestamp
-------------------------------+-------------------------------
2015-09-25 00:26:24.900512+09  | 2015-09-25 00:26:27.229012+09
(1 row)

postgres=#

トランザクションを開始していない場合はnow()とclock_timestamp()両方ともほぼ同じ値を表示しますが、トランザクション開始することによってnow()はトランザクション開始時間で固定されてしまいます。

対処方法

伝統的なPostgreSQL関数と言われているnow()ですが、トランザクション内で使用しかつ現在時刻を取得したい場合はclock_timestamp()を使用するのがいいようです。

 ORACLEとの互換に注意

ORACLEのSYSDATE、SYSTIMESTAMPはトランザクションに関わらず現在時刻を取得するので、ORACLE⇔PostgreSQL移行をする際は注意が必要ですね。

-技術・開発
-