ほんじゃらねっと

ダイエット中プログラマのブログ

PostgresqlのSELECT句での関数呼び出し順序を確認した

f:id:piro_suke:20161029024850j:plain

チーム内の雑談で、

Delete-Insert処理を1つのSQL文で行うとしたら、

SELECT文のSELECT句でDELETE用SPとINSERT用SPを呼び出す方法もあるよね、

SELECT句って記述順に実行してくれるのかな?

みたいな話になったので、検証してみた。

検証してみる

検証環境はCentOS環境上のPostgreSQL 9.5。

SPを使うのはちょっと面倒なので、

タイムスタンプを取得する関数で試してみる。

current_timestampやnow()は何度呼び出してもトランザクション開始時の時刻を

返してくれちゃうので、実際の現在時刻を返すclock_timestamp()を使う。

9.9. 日付/時刻関数と演算子

select clock_timestamp() as x, clock_timestamp() as y;

結果:

               x               |               y
-------------------------------+-------------------------------
 2016-10-29 01:28:21.347312+09 | 2016-10-29 01:28:21.347314+09
(1 行)

順序通りに実行されてるようだ。

一方now()だとこうなる。

select now() as x, now() as y;

結果:

               x               |               y
-------------------------------+-------------------------------
 2016-10-29 01:15:41.942841+09 | 2016-10-29 01:15:41.942841+09
(1 行)

上記のマニュアルページでpg_sleepという遅延実行関数を見つけたので、

clock_timestamp()の間に1秒のsleep処理を挟んで試してみる。

select clock_timestamp() as x, pg_sleep(1), clock_timestamp() as y, pg_sleep(1), clock_timestamp() as z;

結果:

               x               | pg_sleep |              y               | pg_sleep |               z
-------------------------------+----------+------------------------------+----------+-------------------------------
 2016-10-29 01:29:11.397228+09 |          | 2016-10-29 01:29:12.39835+09 |          | 2016-10-29 01:29:13.399481+09
(1 行)

ちゃんと1秒間隔で関数が実行されており、期待通りの良い感じ。

FROM句での実行についても試してみる。

select
    t1.t as x,
    t2.t as y, 
    t3.t as z, 
    t1.t as x2
from
    (select clock_timestamp() as t, pg_sleep(1)) as t1,
    (select clock_timestamp() as t, pg_sleep(1)) as t2, 
    (select clock_timestamp() as t, pg_sleep(1)) as t3
;

結果:

               x               |               y               |               z               |              x2
-------------------------------+-------------------------------+-------------------------------+-------------------------------
 2016-10-29 01:31:41.524409+09 | 2016-10-29 01:31:42.525554+09 | 2016-10-29 01:31:43.526694+09 | 2016-10-29 01:31:41.524409+09
(1 行)

x(t1)->y(t2)->z(t3)のFROM句記述順で実行されてる。

x2は確認用にxと同じt1の結果を表示しており、xと同じ値を返してるので

FROM句の処理時のタイムスタンプが返されてることが分かる。

一応、SELECT句での呼び出しではなくFROM句の順序に依存していることを

確認するために、FROM句の順序を入れ替えてみる。

select
    t1.t as x,
    t2.t as y, 
    t3.t as z, 
    t1.t as x2
from
    (select clock_timestamp() as t, pg_sleep(1)) as t3,
    (select clock_timestamp() as t, pg_sleep(1)) as t2, 
    (select clock_timestamp() as t, pg_sleep(1)) as t1
;
               x               |               y               |               z               |              x2               
-------------------------------+-------------------------------+-------------------------------+-------------------------------
 2016-10-29 02:33:01.384055+09 | 2016-10-29 02:33:00.383529+09 | 2016-10-29 02:32:59.382388+09 | 2016-10-29 02:33:01.384055+09
(1 行)

z(t1)->y(t2)->x(t3)のFROM句記述順で実行されてるようだ。

with句でも試してみよう。

with
t1 as (select clock_timestamp() as t, pg_sleep(1))
,t2 as (select clock_timestamp() as t, pg_sleep(1))
,t3 as (select clock_timestamp() as t, pg_sleep(1))
select 
    t1.t as x, 
    t2.t as y, 
    t3.t as z, 
    t1.t as x2 
from
    t1,t2,t3
;

結果:

               x               |               y               |               z               |              x2
-------------------------------+-------------------------------+-------------------------------+-------------------------------
 2016-10-29 03:12:55.630785+09 | 2016-10-29 03:12:56.632065+09 | 2016-10-29 03:12:57.633293+09 | 2016-10-29 03:12:55.630785+09
(1 行)

FROM句入れ替え版

with
t1 as (select clock_timestamp() as t, pg_sleep(1))
,t2 as (select clock_timestamp() as t, pg_sleep(1))
,t3 as (select clock_timestamp() as t, pg_sleep(1))
select 
    t1.t as x, 
    t2.t as y, 
    t3.t as z, 
    t1.t as x2 
from
    t3,t2,t1
;
              x              |               y               |               z               |             x2
-----------------------------+-------------------------------+-------------------------------+-----------------------------
 2016-10-29 03:13:39.9427+09 | 2016-10-29 03:13:38.941544+09 | 2016-10-29 03:13:37.940425+09 | 2016-10-29 03:13:39.9427+09
(1 行)

with句の記述順ではなく、FROM句の呼び出し順で実行されている。

おわり

SELECT句もFROM句も関数呼び出しは記述順で実行してくれるようなので、

Delete用SPとInsert用SPをSELECT句で並べて実行する方法は

(それが良い方法かどうかはともかくとして)うまくいきそう。

clock_timestamp()とpg_sleep()は良い発見だった。

PostgreSQL徹底入門 第3版

PostgreSQL徹底入門 第3版

  • 作者: 笠原辰仁,北川俊広,坂井潔,坂本昌彦,佐藤友章,石井達夫
  • 出版社/メーカー: 翔泳社
  • 発売日: 2011/02/02
  • メディア: 大型本
  • 購入: 3人 クリック: 28回
  • この商品を含むブログ (6件) を見る