ITPub博客

首页 > Linux操作系统 > Linux操作系统 > PG 优化器的精彩

PG 优化器的精彩

原创 Linux操作系统 作者:babyyellow 时间:2012-08-02 15:58:12 0 删除 编辑
我们先看下面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/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: lisp 习题 our-union
请登录后发表评论 登录
全部评论
oracle MySQL Postgresql 专职数据库dba。 系统架构师。 mysql 官方认知dba 。 15年专职dba 经验。 潜意识沟通实证者 心理咨询师。 禅修布道者, 禅修指导员。 禅定实证者。

注册时间:2010-12-02

  • 博文量
    367
  • 访问量
    1908852