PostgreSQL SRF (set-returning functions) 函数where, index实现

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介:

标签

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

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
2月前
|
关系型数据库 Serverless 定位技术
PostgreSQL GIS函数判断两条线有交点的函数是什么?
PostgreSQL GIS函数判断两条线有交点的函数是什么?
240 60
|
15天前
|
Java Python
gc模块的set_threshold函数
gc模块的set_threshold函数
|
2月前
|
SQL XML Java
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
文章介绍了MyBatis中动态SQL的用法,包括if、choose、where、set和trim标签,以及foreach标签的详细使用。通过实际代码示例,展示了如何根据条件动态构建查询、更新和批量插入操作的SQL语句。
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
|
3月前
|
SQL 自然语言处理 关系型数据库
在 PostgreSQL 中使用 `REPLACE` 函数
【8月更文挑战第8天】
860 9
在 PostgreSQL 中使用 `REPLACE` 函数
|
2月前
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)
|
3月前
|
关系型数据库 PostgreSQL
PostgreSQL的null值函数
【8月更文挑战第20天】PostgreSQL的null值函数
91 3
|
4月前
|
存储 JSON 关系型数据库
mysql中find_in_set()函数用法详解及增强函数
总结而言,`FIND_IN_SET()`是MySQL中处理由逗号分隔的字符串列表的一种便捷方法,尤其适用于列表相对较短且不经常更改的场景。然而,对于更为复杂的需要高性能和可扩展性的数据库设计,它可能不是最优选择,应考虑使用更加正规化的数据库结构。
543 2
mysql中find_in_set()函数用法详解及增强函数
|
3月前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
361 0
|
4月前
|
SQL Oracle 关系型数据库
|
4月前
|
关系型数据库 BI 数据处理

相关产品

  • 云原生数据库 PolarDB