我们先看下面sql:[code]
postgres=# SELECT
postgres-# (
postgres(# SELECT string_agg(x, '')
postgres(# FROM (
postgres(# SELECT chr(ascii('a') + floor(random() * 26)::integer)
postgres(# FROM generate_series(1, 40 + b * 0) as f(g)
postgres(# ) AS y(x)
postgres(# ) AS result
postgres-# FROM generate_series(1,5) as a(b);
result
------------------------------------------
oltxgwlsjdueshyjeiydcasfslbnpjzevsbcpnuz
rpdjxcsbkrfnrytkjvxzfweapgcftxelnhulknmv
esiwrchbxeacbfdqlfwfdaqqilbsyondhwayyhzw
maynfberhaxkaobjzdbysobzlcyjkyfwyejegowo
ptzphazgeaewpgwaivkttqpruzwbnspcmostprau
(5 DD????)
postgres=# SELECT
(
SELECT string_agg(x, '')
FROM (
SELECT chr(ascii('a') + floor(random() * 26)::integer)
FROM generate_series(1, 40 ) as f(g)
) AS y(x)
) AS result
FROM generate_series(1,5) as a(b);
result
------------------------------------------
sfrhmniujsncidudcqeqjutvjmpzeptwvlehymci
sfrhmniujsncidudcqeqjutvjmpzeptwvlehymci
sfrhmniujsncidudcqeqjutvjmpzeptwvlehymci
sfrhmniujsncidudcqeqjutvjmpzeptwvlehymci
sfrhmniujsncidudcqeqjutvjmpzeptwvlehymci
[/code]上面的sql 返回了5笔长度为40的随机的字符串。
下面的sql 返回了5笔重复的字符串。 在我们的印象里,b*0 =0 40+0 =40 加与不加结果应该是一样的。
实际上却相差很远。
从下面的sql 看似乎里面的随机数random() 只执行了一次,或者说是缓存了结果集,导致外面的序列,重复的输出了5次。
我们看看他们的执行计划:[code]
postgres=# explain SELECT
postgres-# (
postgres(# SELECT string_agg(x, '')
postgres(# FROM (
postgres(# SELECT chr(ascii('a') + floor(random() * 26)::integer)
postgres(# FROM generate_series(1, 40 + b * 0) as f(g)
postgres(# ) AS y(x)
postgres(# ) AS result
postgres-# FROM generate_series(1,5) as a(b);
QUERY PLAN
----------------------------------------------------------------------------------------
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 f (cost=0.01..25.01 rows=1000 width=0)
(4 DD????)
postgres=#
explain SELECT
(
SELECT string_agg(x, '')
FROM (
SELECT chr(ascii('a') + floor(random() * 26)::integer)
FROM generate_series(1, 40 ) as f(g)
) AS y(x)
) AS result
FROM generate_series(1,5) as a(b);
QUERY PLAN
----------------------------------------------------------------------------------------
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 f (cost=0.00..25.00 rows=1000 width=0)
(4 DD????)
[/code]
两个sql 的执行计划是不同的。pg的优化器 认为第二个sql 中,里面的subquery 是不依赖于外面的sql,所以优化器对他进行了评估计算固定为initplain 这个时候,
跟里面的函数random 的volatile 跟stable 属性是无关的。 这就要引入pg的函数或者表达式的volatile 很stable 属性了所谓的volatile 就是不稳定,即这个函数对同一个输入,可能产生不同的输出。而对于第一个sql ,subquery 应用到了外面sql的变量,导致针对外面sql的每一行都要计算里面的subquery。
我们修改为每次输出100调记录, 第二个sql 用时0.77ms 第一个sql用4.13 ms
也可以看出第一个sql做了更多的活。
针对 函数的volatile 和stable 的属性,再准备下开新帖说明啦,今天到这里了。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/133735/viewspace-739657/
,如需转载,请注明出处,否则将追究法律责任。