标签

PostgreSQL , set-returning functions , SRF , 索引 , 转换


背景

PostgreSQL 函数支持返回多行,定义returns setof type即可。PG内部也内置了蛮多这样的函数,例如

select proname from pg_proc where proretset;  generate_series
unnest  json_array_elements  json_array_elements_text  json_object_keys  json_each  json_each_text  json_to_recordset  unnest  ts_stat  ts_stat  ts_token_type  ts_token_type  ts_parse  ts_parse  jsonb_array_elements  jsonb_array_elements_text  jsonb_object_keys  jsonb_each  jsonb_each_text  jsonb_populate_recordset  jsonb_to_recordset
............

自定义SRF方法如下:

https://www.postgresql.org/docs/11/static/plpgsql-control-structures.html

对于返回多行的函数,如果在where条件中执行过滤,会返回如下错误。

ERROR:  0A000: set-returning functions are not allowed in WHERE

如果要创建基于SRF函数的表达式索引,会报如下错误:

ERROR:  0A000: set-returning functions are not allowed in index expressions

而实际上,可能在场景中有查询srf = ?这样的需求。

如何达到这样的需求呢?

1、 可以将SRF再转换为ARRAY,然后构建ARRAY的GIN索引。

例如这是个例子  postgres=# create or replace function gen_rand(int,int) returns int[] as $$
select array(select (random()*$1)::int from generate_series(1,$2));
$$ language sql strict;
CREATE FUNCTION  postgres=# select gen_rand(100,10);  gen_rand
-------------------------------  {17,5,33,70,54,10,89,96,5,94}
(1 row)

例子

1、建表

create table a (id int, js jsonb);

2、写入测试数据

postgres=# insert into a select id, jsonb_build_array((random()*1000)::int, (random()*1000)::int,(random()*1000)::int,(random()*1000)::int,(random()*1000)::int,(random()*1000)::int,(random()*1000)::int,(random()*1000)::int,(random()*1000)::int,(random()*1000)::int) from generate_series(1,10000) t(id);
INSERT 0 10000

3、数据样本

postgres=# select * from  a limit 2;  id |                        js
----+---------------------------------------------------  1 | [774, 509, 740, 813, 925, 67, 539, 730, 598, 465]  2 | [232, 153, 119, 895, 962, 501, 998, 609, 10, 410]
(2 rows)

4、某个JSON类型的SRF函数调用如下

postgres=# select jsonb_array_elements(js) from  a where id=1;  jsonb_array_elements
----------------------  774  509  740  813  925  67  539  730  598  465
(10 rows)

在WHERE中过滤,创建表达式索引,均报错

postgres=# \set VERBOSITY verbose
postgres=# select * from a where jsonb_array_elements(js) =1;
ERROR:  0A000: set-returning functions are not allowed in WHERE
LINE 1: select * from a where jsonb_array_elements(js) =1;  ^
LOCATION:  check_srf_call_placement, parse_func.c:2258  postgres=# create index idx_a_1 on a (jsonb_array_elements(js));
ERROR:  0A000: set-returning functions are not allowed in index expressions
LINE 1: create index idx_a_1 on a (jsonb_array_elements(js));  ^
LOCATION:  check_srf_call_placement, parse_func.c:2251

5、创建一个UDF,将SRF结果转换为ARRAY

postgres=# create or replace function srf_to_arr(jsonb) returns text[] as $$  select array(select jsonb_array_elements($1)::text);
$$ language sql strict immutable;
CREATE FUNCTION
postgres=# select id,js,srf_to_arr(js) from a limit 1;  id |                        js                         |                srf_to_arr
----+---------------------------------------------------+------------------------------------------  1 | [774, 509, 740, 813, 925, 67, 539, 730, 598, 465] | {774,509,740,813,925,67,539,730,598,465}
(1 row)

6、WHERE srf = ? 条件变成如下

postgres=# select id,js,srf_to_arr(js) from a where srf_to_arr(js) @> array['1'];  id  |                        js                        |               srf_to_arr
------+--------------------------------------------------+-----------------------------------------  18 | [96, 4, 447, 177, 53, 550, 768, 27, 1, 280]      | {96,4,447,177,53,550,768,27,1,280}  67 | [402, 1, 841, 834, 462, 769, 247, 568, 114, 690] | {402,1,841,834,462,769,247,568,114,690}  102 | [555, 599, 389, 719, 1, 916, 910, 637, 566, 36]  | {555,599,389,719,1,916,910,637,566,36}  162 | [687, 1, 628, 851, 20, 522, 883, 814, 874, 938]  | {687,1,628,851,20,522,883,814,874,938}
.....

7、创建表达式索引

postgres=# create index idx_a_1 on a using gin(srf_to_arr(js));
CREATE INDEX

用上了这个GIN倒排索引

postgres=# explain select id,js,srf_to_arr(js) from a where srf_to_arr(js) @> array['1'];  QUERY PLAN
-----------------------------------------------------------------------  Bitmap Heap Scan on a  (cost=3.69..76.70 rows=50 width=160)  Recheck Cond: (srf_to_arr(js) @> '{1}'::text[])  ->  Bitmap Index Scan on idx_a_1  (cost=0.00..3.67 rows=50 width=0)  Index Cond: (srf_to_arr(js) @> '{1}'::text[])
(4 rows)

参考

https://www.postgresql.org/docs/11/static/plpgsql-control-structures.html

PostgreSQL SRF (set-returning functions) 函数where, index实现相关推荐

  1. PostgreSQL仿照Oracle的instr函数

    转自:http://www.myexception.cn/operating-system/480929.html PostgreSQL模仿Oracle的instr函数 -- -- instr fun ...

  2. Python之pandas:pandas中to_csv()、read_csv()函数的index、index_col(不将索引列写入)参数详解之详细攻略

    Python之pandas:pandas中to_csv().read_csv()函数的index.index_col(不将索引列写入)参数详解之详细攻略 目录 pandas中to_csv().read ...

  3. PostgreSQL学习笔记5之函数和操作符一

    一.逻辑操作符: 常用的逻辑操作符有:AND.OR和NOT.其语义与其它编程语言中的逻辑操作符完全相同. 二.比较操作符: 下面是PostgreSQL中提供的比较操作符列表: 操作符 描述 < ...

  4. PostgreSQL 查询数据库中所有函数信息,函数名(全部)

    PostgreSQL 查询数据库中所有函数信息,函数名(全部) selectp .oid,p .proname,p .proargtypes,p .proacl,p .prorettype,p .pr ...

  5. PostgreSQL学习笔记7之函数和操作符三

    九.序列操作函数: 序列对象(也叫序列生成器)都是用CREATE SEQUENCE创建的特殊的单行表.一个序列对象通常用于为行或者表生成唯一的标识符.下面序列函数,为我们从序列对象中获取最新的序列值提 ...

  6. index match函数的使用方法_必学函数组合INDEX+MATCH,秒杀VLOOKUP函数

    VLOOKUP 职场里面用的太频繁的,是必须掌握使用的函数公式,在这个函数的使用过程中,有时候用起来也不是很方便,比如下面两个场景 ❶逆向查找匹配 左边是员工编号,姓名,工资表格数据,现在需要根据姓名 ...

  7. 计算机函数match,秒杀vlookup函数,Index+Match函数组合

    lookup是工作中函数组合. 1.反向查找 [例1]如下图所示,要求根据产品名称,查找编号. 分析: 先利用Match函数根据产品名称在C列查找位置 =MATCH(B13,C5:C10,0) 再用I ...

  8. python find函数 和index的区别_【全网最简单Python教程】--10.列表元素的索引和返回索引值(Index函数使用)...

    在练习日4中,小鱼给大家讲述了神秘的ASCII码编译及解密过程. 在ASCII码中,字符与十进制数字的互相转换是通过 ord()函数和chr()函数. 今天小鱼要给大家介绍另一种在影视剧.侦探小说中更 ...

  9. PostgreSQL MySQL 兼容性之 - bit 函数和操作符

    bit 函数和操作符 MySQL &Bitwise AND <<Left shift >>Shift right BIT_COUNTReturns the number ...

  10. PostgreSQL学习笔记6之函数和操作符二

    六.模式匹配: PostgreSQL中提供了三种实现模式匹配的方法:SQL LIKE操作符,更近一些的SIMILAR TO操作符,和POSIX-风格正则表达式.     1. LIKE:     st ...

最新文章

  1. 解题报告:【kuangbin带你飞】专题四 最短路练习题
  2. 卓越性能代码_开启win10隐藏的“超级性能模式”
  3. hdu3987 最小割边数
  4. 大话ion系列(二)
  5. 硬件:选购CPU和显卡需了解的参数,TDP、SDP、ACP、GCP、TBP是什么?
  6. 基于JAVA+SpringBoot+Mybatis+MYSQL的校园兼职招聘系统
  7. BZOJ 2724: [Violet 6]蒲公英
  8. java中输出进程的映像名称,怎么修改tomcat进程的名称(windows)
  9. Android调试wifi使用wpa_supplicant和wpa_cli总结
  10. sketchup 255个su常用插件)_[插件课堂] SU.KIT发布了v2020,完美支持SketchUp 2020
  11. vs2015注册密钥
  12. 蚂蚁课堂学习笔记之springAop和Ioc
  13. Kolmogorov 的数学观与业绩
  14. 百度关键词地区排名查询php源码,百度关键词地区排名查询
  15. 【mysql 练习题】查询和“01”号同学所学课程完全相同的其他同学的学号
  16. Python 导出微信电子相册中的照片
  17. outlook企业邮箱服务器怎么填,Outlook客户端怎么配置企业邮箱
  18. WLC-WLC升级(以2504为例)
  19. 物质的折射率和光的折射率的关系
  20. Google大数据三大论文

热门文章

  1. 警告: A docBase inside the host appBase has been specified, and will be ignore
  2. 台式计算机电源接线图,​台式机硬盘电源线接法【图解】
  3. android studio图形验证码,android 一行代码,快速实现图片验证码(附android studio 版小demo)...
  4. html 小游戏 俄罗斯方块
  5. Cocos Creator中的Tween
  6. [iOS]手把手教你实现微信小视频
  7. Nginx 配置长连接
  8. 苹果双系统 计算机意外的重新启动,用Boot camp 安装双系统时突然重启,打… - Apple 社区...
  9. 怎么打开服务器的xls文件,xls是什么文件格式?.xls文件打开方法
  10. 戴尔电脑风扇声音大的解决方法