Postgresql 9.5使用jsonb_set更新JSON字段时性能下降

时间:2017-01-16 08:58:04

标签: postgresql jsonb postgresql-9.5

使用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

谢谢

0 个答案:

没有答案