百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

PostgreSQL 优化器知识之-stable 函数调用次数

toyiye 2024-06-21 12:26 10 浏览 0 评论

本文来自阿里云云栖社区,未经许可禁止转载。

更多资讯,尽在云栖科技快讯~

来科技快讯看新闻鸭~

快点关注我认识我爱上我啊~~~


标签

PostgreSQL , 三态 , stable , 调用次数


背景

immutable 函数,输入参数静态时,返回结果不变,所以它在plan前先计算,得到一个常量后,放到QUERY里面再生成执行计划。

stable 函数,输入参数静态时,如果在一个事务中多次调用它,返回结果不变。

显然一个immutable 函数在同一个SQL中,永远只调用一次,(在bind , execute的模式下则只有prepare的时候被调用一次)

但是一个stable函数,虽然输入参数静态时,如果在一个事务中多次调用它,返回结果不变。但是它可能被多次调用。

例如在同一个QUERY中,如果要扫描多条记录时,stable函数可能被多次调用。

1、全表扫描,扫描多少条记录,就需要调用多少次。(同时对于有静态参数输入或无参数的stable函数,需要再加一次执行计划时的评估)

2、索引扫描:

需要区分STABLE函数输入的是静态还是动态参数(或volatile函数的返回值作为参数)。

静态参数,索引扫描时只需要调用两次(不管扫描多少索引条目),一次是执行计划,一次是索引扫描前计算stable函数的返回值,然后就是索引扫了。

如果stable函数输入的是动态参数,不支持索引。所以只可能走全表。

例子

1、创建一个stable函数,里面通过raise来输出信息,判断这个函数被调用了多少次。

无输入参数

postgres=# create or replace function ff() returns int as $ 
declare 
begin 
 raise notice 'a'; 
 return 1; 
end; 
$ language plpgsql strict stable; 
CREATE FUNCTION 

2、创建测试表

postgres=# create table test123(id int); 
CREATE TABLE 
postgres=# insert into test123 values (1),(2),(3); 
INSERT 0 3 

3、生成执行计划时,stable函数被执行一次(指无动态参数的stable函数,有动态参数的,不执行)

postgres=# explain select * from test123 where id=ff(); 
NOTICE: a 
 QUERY PLAN 
---------------------------------------------------------- 
 Seq Scan on test123 (cost=0.00..679.38 rows=13 width=4) 
 Filter: (id = ff()) 
(2 rows) 

4、使用全表扫描,有多少记录就会被执行多少次,同时加上一次执行计划的评估,一共调用了4次

postgres=# select * from test123 where id=ff(); 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
 id 
---- 
 1 
(1 row) 

5、创建索引

postgres=# create index idx_test123 on test123(id); 
CREATE INDEX 

6、强制使用索引扫描

postgres=# set enable_seqscan=off; 
SET 

7、生成执行计划,调用一次

postgres=# explain select * from test123 where id=ff(); 
NOTICE: a 
 QUERY PLAN 
-------------------------------------------------------------------------------- 
 Index Only Scan using idx_test123 on test123 (cost=0.38..2.60 rows=1 width=4) 
 Index Cond: (id = ff()) 
(2 rows) 

8、执行+执行计划,分别调用一次

postgres=# select * from test123 where id=ff(); 
NOTICE: a 第一次生成执行计划 
NOTICE: a 第二次是索引扫描前的函数值计算 
 id 
---- 
 1 
(1 row) 

9、新增一条数据

postgres=# insert into test123 values (1); 
INSERT 0 1 

10、符合条件的数据有2条,不影响索引扫描时,无参数或无动态参数的stable函数的调用次数

postgres=# select * from test123 where id=ff(); 
NOTICE: a 
NOTICE: a 
 id 
---- 
 1 
 1 
(2 rows) 
postgres=# select * from test123 where id>ff(); 
NOTICE: a 
NOTICE: a 
 id 
---- 
 2 
 3 
(2 rows) 
 
postgres=# select * from test123 where id>=ff(); 
NOTICE: a 
NOTICE: a 
 id 
---- 
 1 
 1 
 2 
 3 
(4 rows) 
 
postgres=# explain analyze select * from test123 where id>ff(); 
NOTICE: a 
NOTICE: a 
 QUERY PLAN 
--------------------------------------------------------------------------------------------------------------------- 
 Index Scan using idx_test123 on test123 (cost=0.38..2.60 rows=1 width=4) (actual time=0.067..0.070 rows=2 loops=1) 
 Index Cond: (id > ff()) 
 Planning time: 0.185 ms 
 Execution time: 0.127 ms 
(4 rows) 

11、创建一个带参数的stable函数

create or replace function ff(int) returns int as $ 
declare 
begin 
 raise notice 'a'; 
 return 1; 
end; 
$ language plpgsql strict stable; 

12、插入10条重复值

postgres=# insert into test123 select 1 from generate_series(1,10); 
INSERT 0 10 

13、使用静态参数输入时,可以走索引,所以依旧只调用2次。

postgres=# select * from test123 where id>ff(1); 
NOTICE: a 执行计划 
NOTICE: a 索引扫描前固定stable函数值 
 id 
---- 
 2 
 3 
(2 rows) 
postgres=# explain select * from test123 where id>ff(1); 
NOTICE: a 
 QUERY PLAN 
--------------------------------------------------------------------------- 
 Index Scan using idx_test123 on test123 (cost=0.38..2.60 rows=1 width=4) 
 Index Cond: (id > ff(1)) 
(2 rows) 

14、改成动态参数,那么就不能走索引扫描,调用次数等于记录数,因为explain时也不会被调用

调用了14次。

postgres=# explain analyze select * from test123 where id>ff(id); 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
 QUERY PLAN 
--------------------------------------------------------------------------------------------------------------------- 
 Seq Scan on test123 (cost=10000000000.00..10000000001.79 rows=1 width=4) (actual time=0.085..0.159 rows=2 loops=1) 
 Filter: (id > ff(id)) 
 Rows Removed by Filter: 12 
 Planning time: 0.085 ms 
 Execution time: 0.197 ms 
(5 rows) 
 
postgres=# select * from test123 where id>ff(id); 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
NOTICE: a 
 id 
---- 
 2 
 3 
(2 rows) 
 
postgres=# select count(*) from test123; 
 count 
------- 
 14 
(1 row) 

相关推荐

Python 的hash 函数(python的hash函数)

今天在看python的hash函数源码的时候,发现针对不同的数据类型python实现了不同的hash函数,今天简单介绍源码中提到的hash函数。(https://github.com/pyth...

8款Python GUI开源框架,谁才是你的菜?

作为Python开发者,你迟早都会用到图形用户界面来开发应用。本文千锋武汉Python培训小编将推荐一些PythonGUI框架,希望对你有所帮助。1、Python的UI开发工具包Kivy...

python适合开发桌面软件吗?(python可不可以开发桌面应用软件)

其实Python/Java/PHP都不适合用来做桌面开发,Java还是有几个比较成熟的产品的,比如大名鼎鼎的Java集成开发环境IntelliJIDEA、Eclipse就是用Java开发的,不过PH...

CryptoChat:一款功能强大的纯Python消息加密安全传输工具

关于CryptoChatCryptoChat是一款功能强大的纯Python消息加密安全传输工具,该工具专为安全研究专家、渗透测试人员和红蓝队专家设计,该工具可以完全保证数据传输中的隐私安全。该工具建立...

为什么都说Python简单,但我觉得难?

Python普遍被大家认为是编程语言中比较简单的一种,但有一位电子信息的学生说自己已经学了C语言,但仍然觉得Python挺难的,感觉有很多疑问,像迭代器、装饰器什么的……所以他提出疑问:Python真...

蓝牙电话-关联FreeSwitch中继SIP账号通过Rest接口

蓝牙电话-关联FreeSwitch中继SIP账号通过Rest接口前言上一篇章《蓝牙电话-与FreeSwitch服务器和UA坐席的通话.docx》中,我们使用开源的B2B-UA当中经典的FreeSWIT...

技术分享|Sip与WebRTC互通-SRProxy开源库讲解

SRProxy介绍目前WebRTC协议跟SIP协议互通场景主要运用在企业呼叫中心、企业内部通信、电话会议(PSTN)、智能门禁等场景,要想让WebRTC与SIP互通,要解决两个层面的...

全网第N篇SIP协议之GB28181注册 JAVA版本

鉴于网上大部分关于SIP注册服务器编写都是C/C++/python,故开此贴,JAVA实现也贴出分享GB28181定义了了基于SIP架构的视频监控互联规范,而对于多数私有协议实现的监控系统...

「linux专栏」top命令用法详解,再也不怕看不懂top了

在linux系统中,我们经常使用到的一个命令就是top,它主要是用来显示系统运行中所有的进程和进程对应资源的使用等信息,所有的用户都可以使用top命令。top命令内容量丰富,可令使用者头疼的是无法全部...

Linux 中借助 perf 对 php 程序模拟CPU高的案例分析

导语本文是一篇Linux借助工具分析CPU高的优化案例,没有任何干货内容,很详细的展示了优化CPU高的具体步骤,非常适合初中级读者阅读!...

centos漏洞处理方法(centos podman)

centos服务器最近有诸多漏洞,修复命令及对应的漏洞整理后,分享给大家RHSA-2020:1176-低危:avahi安全更新yumupdateavahi-libsRHSA-2017:326...

Linux上的free命令详解(Buffer和Cache)

解释一下Linux上free命令的输出。下面是free的运行结果,一共有4行。为了方便说明,我加上了列号。这样可以把free的输出看成一个二维数组FO(FreeOutput)。例如:FO[2][1]...

linux 命令行之你真的会用吗?--free 基本用法篇

free命令行统计内存使用率及swap交换分区的使用率数据。是由sourceforge负责维护的,在ubuntu上其包名为procps,这个源码包中,除了free还有ps,top,vmstat,ki...

kong api gateway 初体验(konga github)

kongapigateway初体验(firstsight?)。Kong是一个可扩展的开源API层(也称为API网关或API中间件)。Kong运行在任何RESTfulAPI的前面,并通过插件...

在Ubuntu下开启IP转发的方法(ubuntu20 ip)

IP地址分为公有ip地址和私有ip地址,PublicAddress是由INIC(internetnetworkinformationcenter)负责的,这些IP地址分配给了注册并向INIC提...

取消回复欢迎 发表评论:

请填写验证码