使用jsonb_set替换jsonb字段的值时出现性能问题。
似乎每次在JSONB表达式中替换值时,更新字段的时间都会增加。
这是我的测试表:
CREATE TABLE IF NOT EXISTS TEMP_package_var(
id VARCHAR,
val jsonb
);
我的测试功能是:
create or replace function set_package_var_any(package_name text, var_name text, var_subname text, var_value anyelement) returns VOID as $func$
DECLARE
wk_var jsonb;
wk_mainvar jsonb;
wk_newvar jsonb;
wk_name text := lower(var_name);
wk_subname text := lower(var_subname);
start_at timestamp;
end_at timestamp;
BEGIN
select val from TEMP_package_var INTO wk_var WHERE id = lower(package_name);
if not found then
insert into TEMP_package_var(id, val) values(lower(package_name),jsonb_build_object(wk_name, jsonb_build_object(wk_subname, var_value)));
return;
end if;
wk_subname := var_name || ',' || wk_subname;
start_at := clock_timestamp();
UPDATE TEMP_package_var SET val = jsonb_set(wk_var, string_to_array(wk_subname,','), to_jsonb(var_value), true) WHERE id = lower(package_name);
end_at := clock_timestamp();
raise notice 'UPDATE Time__________________________________________: % - [%]', end_at - start_at, var_value;
END;
$func$
LANGUAGE PLPGSQL
SECURITY DEFINER;
我的主要功能是:
CREATE OR REPLACE FUNCTION pkgvar_set_test(loops bigint, rerun bigint) returns void as $body$
declare
start_at timestamp;
end_at timestamp;
begin
start_at := clock_timestamp();
for ix0 in 1 .. rerun loop
for ix in 1 .. loops loop
perform set_package_var_any('package_name', 'var_name', 'var_name_'||to_char(ix,'FM00000'), 'var_value_'||to_char(ix0,'FM00000')||'_'||to_char(ix,'FM00000'));
end loop;
end loop;
end_at := clock_timestamp();
raise notice 'time is %', end_at - start_at;
end;
$body$
LANGUAGE PLPGSQL
SECURITY DEFINER;
然后我多次执行main函数。
测试如下:
select pkgvar_set_test(2,2);
这将创建以下JSONB行:
{"var_name": {"var_name_00001": "var_value_00001_00001", "var_name_00002": "var_value_00001_00002"}}
然后替换值:
{"var_name": {"var_name_00001": "var_value_00002_00001", "var_name_00002": "var_value_00002_00002"}}
但在使用更多记录进行相同测试时
第一次:
select pkgvar_set_test(50,50);
NOTICE: time is 00:00:00.667468
第二次:
select pkgvar_set_test(50,50);
NOTICE: time is 00:00:01.348275
第三次:
select pkgvar_set_test(50,50);
NOTICE: time is 00:00:01.920818
等等,你可以看到替换变得越来越慢。 我理解第一个循环和第二个循环之间的区别,但我无法弄清楚的是为什么值会随着执行次数的增加而增加。
有人可以帮帮我吗?
Postgresql: 9.5.2
OS: Centos 7.1
谢谢