PostgreSQLSRF(set-returningfunctions)函式where,index實現
標籤
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
相關文章
- numpy.where()函式函式
- mysql函式substring_index實現split切割效果MySql函式Index
- oracle實驗記錄 (函式index)Oracle函式Index
- (函式)實現strstr函式函式
- mysql 函式substring_index()MySql函式Index
- MySQL排名函式實現MySql函式
- MySQL分析函式實現MySql函式
- fcntl函式實現dup函式
- excel index match 函式怎麼用ExcelIndex函式
- 在select 中的where 中使用indexIndex
- JavaScript的迭代函式與迭代函式的實現JavaScript函式
- 函式節流、函式防抖實現原理分析函式
- async 函式的實現原理函式
- 去抖函式的實現函式
- Golang實現PHP常用函式GolangPHP函式
- Go實現PHP常用函式GoPHP函式
- bind 函式的實現原理函式
- mysql實現開窗函式MySql函式
- atoi函式簡單實現函式
- 實現c中memcpy函式memcpy函式
- 【面試】shuffle函式的實現面試函式
- js實現函式過載JS函式
- 關於函式索引(function-based index)函式索引FunctionIndex
- 實現call函式,手寫Function.prototype.call函式函式Function
- 使用函式式實現觀察者模式模式函式模式
- match函式簡單介紹以及與index函式結合應用函式Index
- SQL優化] 避免在WHERE子句中對列使用函式SQL優化函式
- (函式分治法)實現pow函式(x的y次方冪)函式
- 不使用日期函式實現ADD_MONTHS函式功能函式
- 一個有用的函式-實現dump函式的convert!函式
- Vue元件實現函式防抖Vue元件函式
- Vue實現函式防抖元件Vue函式元件
- 函式實現閏年判斷函式
- PHP中實現函式過載PHP函式
- PHP內建字串函式實現PHP字串函式
- 虛擬函式的實現原理函式
- 巧妙地實現 debugOnly 函式Go函式
- Golang之不可重入函式實現Golang函式