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,所以,我希望任何表达式都依赖于它也是 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,则将其评估为 一次InitPlan,并且其中表达式的易变性与否无关紧要。通过引入子查询对 的依赖性a,即使其成为相关子查询,必须对 的每一行重新进行评估a

于 2012-07-25T11:09:53.170 回答