PostgreSQL 日付の関数について

どうも 村上です。

最近PostgreSQLを使ってて「おぅ!!」ってなった内容です。

トランザクション中におけるnow()関数について

データコンバートをするためにSQLをちょこちょこ実行してたら不思議なことが起こりました。

全部同じ時間が返る!?
※ 高速でコマンドを叩いているわけではないです!!

こんな記述が
9.9. 日付/時刻関数と演算子

一部抜粋
これらの関数は、現在のトランザクションの開始時刻を返します。 この値は、トランザクションが実行されている間は変化しません。 これは、次の機能を検討した結果です。 単一トランザクションで、"current"時間を一貫性を持った表現を行うことができるようにすることを目的とし、このため、同一トランザクションで何回変更を行っても同一のタイムスタンプを生成します。

そして注意書きに
注意: 他のデータベースシステムでは、これらの値をより頻繁に増加させることがあります。
ともありました。

トランザクション中に現在時刻を取得するには?

PostgreSQLにはいろいろと時間を取得する関数があります。

マニュアルによると、
CURRENT_TIMESTAMP = now() = transaction_timestamp()
です。
また
statement_timestamp()は現在の文の実行開始時刻を返す
clock_timestamp()は実際の現在時刻を返す

とあります。

ではやってみよう!!

トランザクションなし

間隔は村上体内時計の5秒です。

clock_timestampとそれ以外で時間が0.0002秒ほど違います。

トランザクションあり

こちらも村上体内時計で5秒間隔です。

マニュアル通りCURRENT_TIMESTAMP、now()、transaction_timestamp()はトランザクション開始時刻を返しています。
statement_timestamp()とclock_timestamp()は実行されている時間を返しているようですが、時間が0.0002秒ほど時間が違います。

INSERTとUPDATEでは!?

SELECTをするとINSERTとUPDATEが気になりますよね?
やってみました。

INSERT

というテーブルの下記のSQLを流します。

以前鈴木さんが書かれていた集合関数を使いました。
PostgreSQL: 集合を返すGENERATE_SERIES関数で大量データを生成して集計する

すべてのレコードは確認できないので、それぞれのminとmaxを取ってみました。

clock_timestamp()とそれ以外で時間が違います。
また、clock_timestamp()のminとmaxでも値が違います。

UPDATE

続いてUPDATE

そして結果

INSERTと結果が同じですね。(当然ちゃ当然。。。)

まとめ

ということで、PostgreSQLの現在時刻を取得する関数を見て来ました。

結果として、トランザクション開始時の時刻を返すものと関数実行時の時刻を返すものがあるということ。
statement_timestamp()とclock_timestamp()は同じものを返さない。(なぜかは謎。。。)
ということがわかりました。

他のDBMSではトランザクション内では現在時刻を返していたので、この仕様を知った時には驚きました。
PostgreSQLを初めて使う時には注意ですね。

Comments are closed, but you can leave a trackback: Trackback URL.

Comments

  • わんこ  On 2014年9月4日 at 14:25

    ちょっと古い記事にコメントですが。

    まとめに
    「statement_timestamp()とclock_timestamp()は同じものを返さない。(なぜかは謎。。。)」
    とありますが、仕様なので当然ですよね。名前のまんま。
    statement_timestampはステートメント開始時刻なので、同一トランザクション内で2つSQLあった場合、
    1と2では返す値が違うのでは?clock_timestamp()は現在時刻。
    マニュアルに書いてあります。
    厳密にいうと、トランザクション開始時の時刻、ステートメント開始時刻、関数実行時の時刻の3種類ですね!