• 金仓数据库KingbaseES immutable 与 stable 函数的差异


    目录

    1、准备数据

    2、创建immutable 和 stable 函数

    3、单独explain 函数

    4、例子一

    5、例子二


    Stable 函数不能修改数据库,单个Query中所有行给定同样的参数确保返回相同的结果。这种稳定级别允许优化器将多次函数调用转换为一次。在索引扫描的条件中使用这种函数是可行的,因为索引扫描只计算一次比较值(comparison value),而不是每行都计算一次。

    Immutable 函数不能修改数据库,在任何情况下,只要输入参数相同,返回结果就相同。这种级别的函数,优化器可以提前进行计算,在查询过程中作为常量参数。比如:SELECT...WHERE x=2+2 可以简化为SELECT...WHERE x=4。

    以下以例子说明二者的差异。

    1、准备数据

    1. create table t1(id1 integer,id2 integer);
    2. insert into t1 select generate_series(1,10000000),generate_series(1,10000000);
    3. test=# \timing on
    4. Timing is on.
    5. test=# select count(*) from t1;
    6. count
    7. ----------
    8. 10000000
    9. (1 row)
    10. Time: 681.445 ms

    2、创建immutable 和 stable 函数

    1. create or replace function f001()
    2. returns bigint
    3. immutable
    4. language sql
    5. as
    6. $$ select count(*) from t1 $$ ;
    7. create or replace function f002()
    8. returns bigint
    9. stable
    10. language sql
    11. as
    12. $$ select count(*) from t1 $$ ;

    3、单独explain 函数

    可以看到对于 immutable 函数,在 explain 时,实际会去执行的;而stable 函数,explain 时则不会实际执行。

    1. test=# explain select f001();
    2. QUERY PLAN
    3. ------------------------------------------
    4. Result (cost=0.00..0.01 rows=1 width=8)
    5. (1 row)
    6. Time: 450.572 ms
    7. test=# explain select f002();
    8. QUERY PLAN
    9. ------------------------------------------
    10. Result (cost=0.00..0.26 rows=1 width=8)
    11. (1 row)
    12. Time: 0.641 ms
    13. test=# select f001();
    14. f001
    15. ----------
    16. 10000000
    17. (1 row)
    18. Time: 448.720 ms
    19. test=# select f002();
    20. f002
    21. ----------
    22. 10000000
    23. (1 row)
    24. Time: 426.745 ms

    4、例子一

    可以看到 immutable 函数执行时间主要花在planning上,也就是在制定执行计划前,就已经取得函数的值;而 stable 函数,则在语句解析和执行时,都要执行函数,而且,针对语句的访问的每个tuple,都要执行一次函数调用。

    1. test=# explain analyze select * from (select * from t1 limit 10) a where a.id1=f001();
    2. QUERY PLAN
    3. ---------------------------------------------------------------------------------------------------------------------
    4. Subquery Scan on a (cost=0.00..0.27 rows=1 width=8) (actual time=0.012..0.013 rows=0 loops=1)
    5. Filter: (a.id1 = '10000000'::bigint)
    6. Rows Removed by Filter: 10
    7. -> Limit (cost=0.00..0.15 rows=10 width=8) (actual time=0.009..0.010 rows=10 loops=1)
    8. -> Seq Scan on t1 (cost=0.00..148609.21 rows=10007621 width=8) (actual time=0.008..0.009 rows=10 loops=1)
    9. Planning Time: 413.963 ms
    10. Execution Time: 0.026 ms
    11. (7 rows)
    12. test=# explain analyze select * from (select * from t1 limit 10) a where a.id1=f002();
    13. QUERY PLAN
    14. ---------------------------------------------------------------------------------------------------------------------
    15. Subquery Scan on a (cost=0.00..2.77 rows=1 width=8) (actual time=3691.788..3691.788 rows=0 loops=1)
    16. Filter: (a.id1 = f002())
    17. Rows Removed by Filter: 10
    18. -> Limit (cost=0.00..0.15 rows=10 width=8) (actual time=0.012..0.028 rows=10 loops=1)
    19. -> Seq Scan on t1 (cost=0.00..148609.21 rows=10007621 width=8) (actual time=0.011..0.021 rows=10 loops=1)
    20. Planning Time: 364.233 ms
    21. Execution Time: 3691.807 ms
    22. (7 rows)
    23. Time: 4056.907 ms (00:04.057)
    24. test=# explain analyze select * from (select * from t1 where 1=2) a where a.id1=f002();
    25. QUERY PLAN
    26. ------------------------------------------------------------------------------------------
    27. Result (cost=0.00..2675533.51 rows=1 width=8) (actual time=0.001..0.001 rows=0 loops=1)
    28. One-Time Filter: false
    29. -> Seq Scan on t1 (cost=0.00..2675533.51 rows=1 width=8) (never executed)
    30. Filter: (id1 = f002())
    31. Planning Time: 490.720 ms
    32. Execution Time: 0.017 ms
    33. (6 rows)
    34. test=# explain analyze select * from (select * from t1 limit 1) a where a.id1=f002();
    35. QUERY PLAN
    36. --------------------------------------------------------------------------------------------------------------------
    37. Subquery Scan on a (cost=0.00..0.28 rows=1 width=8) (actual time=390.833..390.834 rows=0 loops=1)
    38. Filter: (a.id1 = f002())
    39. Rows Removed by Filter: 1
    40. -> Limit (cost=0.00..0.01 rows=1 width=8) (actual time=0.024..0.053 rows=1 loops=1)
    41. -> Seq Scan on t1 (cost=0.00..148609.21 rows=10007621 width=8) (actual time=0.023..0.023 rows=1 loops=1)
    42. Planning Time: 426.693 ms
    43. Execution Time: 390.852 ms
    44. (7 rows)

    5、例子二

    sysdate 函数 为 stable 时:sysdate 函数在同一事务内多次执行返回的结果都相同,跨事务则每次结果不同。

    1. test=# begin
    2. test-# for i in 1..5 loop
    3. test-# raise notice '%', sysdate();
    4. test-# perform sys_sleep(1);
    5. test-# commit;
    6. test-# end loop;
    7. test-# end;
    8. test-# /
    9. NOTICE: 2022-06-29 19:53:18
    10. NOTICE: 2022-06-29 19:53:19
    11. NOTICE: 2022-06-29 19:53:20
    12. NOTICE: 2022-06-29 19:53:21
    13. NOTICE: 2022-06-29 19:53:22
    14. ANONYMOUS BLOCK
    15. Time: 5011.031 ms (00:05.011)
    16. test=# begin
    17. test-# for i in 1..5 loop
    18. test-# raise notice '%', sysdate();
    19. test-# perform sys_sleep(1);
    20. test-# end loop;
    21. test-# end;
    22. test-# /
    23. NOTICE: 2022-06-29 19:54:14
    24. NOTICE: 2022-06-29 19:54:14
    25. NOTICE: 2022-06-29 19:54:14
    26. NOTICE: 2022-06-29 19:54:14
    27. NOTICE: 2022-06-29 19:54:14
    28. ANONYMOUS BLOCK
    29. Time: 5005.724 ms (00:05.006)

    sysdate 函数为 immutable 时:不管是否跨事务,sysdate 函数结果都相同。

    1. test=# alter function sysdate immutable;
    2. ALTER FUNCTION
    3. Time: 6.276 ms<br>
    4. test=# begin
    5. test-# for i in 1..5 loop
    6. test-# raise notice '%', sysdate();
    7. test-# perform sys_sleep(1);
    8. test-# commit;
    9. test-# end loop;
    10. test-# end;
    11. test-# /
    12. NOTICE: 2022-06-29 19:54:58
    13. NOTICE: 2022-06-29 19:54:58
    14. NOTICE: 2022-06-29 19:54:58
    15. NOTICE: 2022-06-29 19:54:58
    16. NOTICE: 2022-06-29 19:54:58
    17. ANONYMOUS BLOCK
    18. Time: 5007.899 ms (00:05.008)<br>
    19. test=# begin
    20. test-# for i in 1..5 loop
    21. test-# raise notice '%', sysdate();
    22. test-# perform sys_sleep(1);
    23. test-# end loop;
    24. test-# end;
    25. test-# /
    26. NOTICE: 2022-06-29 19:55:11
    27. NOTICE: 2022-06-29 19:55:11
    28. NOTICE: 2022-06-29 19:55:11
    29. NOTICE: 2022-06-29 19:55:11
    30. NOTICE: 2022-06-29 19:55:11
    31. ANONYMOUS BLOCK
    32. Time: 5007.694 ms (00:05.008)

     

  • 相关阅读:
    算法练习(三)井字棋
    给 「大模型初学者」 的 LLaMA 3 核心技术剖析
    计算机网络4小时速成:传输层,功能,UDP协议,TCP协议,三次握手,传输数据,四次握手,超时重传,流量控制
    前端工程化工具系列(七)—— PNPM(v9.2.0):高性能的 NPM 替代品
    Spring【@Resource、@Autowired+lombook+Bean的生命周期】
    springmvc第十五个练习(一个拦截器的执行)
    使用项目自动生成的dokcerfile第一次构建时把加载aps5.0失败无法找到加载的文件
    超简单的视差滚动网站
    小程序引入隐私政策
    经验之谈:内存泄露的原因以及分析
  • 原文地址:https://blog.csdn.net/arthemis_14/article/details/128135012