5

Bruce Momjianのブログ投稿「SQLを介したランダムデータの生成」で、彼は次のコードを使用して5つのランダム文字列を生成しました。

SELECT
(
        SELECT string_agg(x, '')
        FROM (
                SELECT chr(ascii('a') + floor(random() * 26)::integer)
                FROM generate_series(1, 40 + b * 0) as f(g)
        ) AS y(x)
) AS result
FROM generate_series(1,5) as a(b);

              result                  
------------------------------------------
 plwfwcgajxdygfissmxqsywcwiqptytjjppgrvgb
 sjaypirhuoynnvqjdgywfsfphuvzqbbilbhakyhf
 ngtabkjfqibwahlicgisijatliuwgbcuiwujgeox
 mqtnyewalettounachwjjzdrvxbbbpzogscexyfi
 dzcstpsvwpefohwkfxmhnlwteyybxejbdltwamsx
(5 rows)

なぜ6行目の「b*0」が必要なのか疑問に思いました。それを削除すると、結果は5つのまったく同じ文字列に変更されました。これは、Postgresが外部の選択式(結果)をキャッシュしたことを意味します。

Postgresで式のキャッシュがどのように機能しているかがわかりませんでした。ドキュメントによると、 random()関数はVOLATILEとマークされているので、それに依存する式も揮発性であると思います。

Postgresで式キャッシングはどのように機能しますか?それはどこかに文書化されていますか?「b*0」がrandom()が無効にしたキャッシュを無効にしたのはなぜですか?

アップデート:

この問題を調査するために、「b * 0」をfloor()呼び出しの内側に移動して、random()と同じ位置/レベルにしました。

...
                SELECT chr(ascii('a') + floor(random() * 26 + b * 0)::integer)
                FROM generate_series(1, 40) as s(f)
...

結果はまだキャッシュされません。異なる文字列。

更新:問題を示す別の例

create sequence seq_test;

SELECT (SELECT nextval('seq_test')) FROM generate_series(1,5);

 ?column? 
----------
        1
        1
        1
        1
        1
(5 rows)
4

1 に答える 1

4

まあ、random()それ自体は揮発性であるため、同じ文字の文字列が最後まで繰り返されることはありません。

クエリの計画を見ると、次のようにb*0なります。

b*0

 Function Scan on generate_series a  (cost=0.00..37530.00 rows=1000 width=4)
   SubPlan 1
     ->  Aggregate  (cost=37.51..37.52 rows=1 width=32)
           ->  Function Scan on generate_series  (cost=0.01..25.01 rows=1000 width=0)

なしb*0

 Function Scan on generate_series a  (cost=37.52..47.52 rows=1000 width=0)
   InitPlan 1 (returns $0)
     ->  Aggregate  (cost=37.50..37.51 rows=1 width=32)
           ->  Function Scan on generate_series  (cost=0.00..25.00 rows=1000 width=0)

内部集約がに依存していないとPostgreSQLが判断した場合a、それは1回として評価され、InitPlan内部の式の変動性は関係ありません。サブクエリの依存性を導入することによりa、つまり相関サブクエリにすることにより、の行ごとに評価をやり直す必要がありますa

于 2012-07-25T11:09:53.170 に答える