如何改进从文件或文件夹路径获取父项的功能?

时间:2016-04-26 10:39:18

标签: performance postgresql plpgsql

这是我从文件或文件夹路径中获取父母的功能:

CREATE OR REPLACE FUNCTION storage.__object_get_parents(p_object_path varchar, p_tolowercase boolean)
RETURNS varchar[] AS
$BODY$
DECLARE
    _arr varchar[];
    _parents varchar[];
    _parent varchar;
    _parent_prev varchar;
    _object_path varchar;
    _cnt int := 0;
    _val varchar;
BEGIN
    if p_tolowercase then
        _object_path := lower(substr(p_object_path, 1, length(p_object_path)-1));
    else
        _object_path := substr(p_object_path, 1, length(p_object_path)-1);
    end if;
    _arr := string_to_array(_object_path, '/', '');
    _parent_prev := '';
    for i in 1 .. array_upper(_arr, 1)-1 loop
        _val := _arr[i];
        if _val IS NOT NULL then
            _parent := _parent_prev || _val || '/';
            _parents := array_append(_parents, _parent);
            _cnt := _cnt + 1;
        else
            -- ignore double slashes: replace previsouly added element
            _parent := _parent_prev || '/';
            _parents[_cnt] := _parent;
        end if;
        _parent_prev := _parent;
    end loop;

    RETURN coalesce(_parents,'{}'::varchar[]);
EXCEPTION
  WHEN OTHERS THEN
    RAISE EXCEPTION 'function __object_get_parents() is failed! ErrCode (%) (%)', SQLSTATE, SQLERRM;
END;
$BODY$
LANGUAGE 'plpgsql' IMMUTABLE;

当我在一个包含许多组件的路径上运行它时,它真的很慢:

select array_length(storage.__object_get_parents('d2140247-ef9d-4d51-ac28-ba008c378720/H%3A/files/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/doc/',false),1);
 array_length 
--------------
         2145
(1 row)

Time: 13885.555 ms

如何提高速度?

2 个答案:

答案 0 :(得分:1)

问题是您正在生成大量数据。如果你有一个长度约为8kB的字符串中的2145个父项,那么你会产生一个2145个元素的数组,这些元素的长度从一个小的开始到接近8kB,平均为4kB。因此,在2145年,父母会产生大约8MB的数据。你真的需要所有这些吗?你真的需要一个函数调用中的所有父母吗?

也许你应该告诉我们你真正想要的东西然后我们可以看到合适的功能是什么。

也就是说,对本地9.5服务器使用get我计划时间为23.8毫秒,运行时间为0.011毫秒。你的问题出在其他地方。

答案 1 :(得分:0)

plpgsql函数通常不提供最快的解决方案,纯SQL解决方案总是会表现得更好,所以你应该首先搜索SQL解决方案(如果你是的话,你可以创建一个sql函数确定要将逻辑包装在函数中。)

递归CTE是您问题的典型解决方案:

with recursive path(path) as (
  values ('d2140247-ef9d-4d51-ac28-ba008c378720//H%3A/files/doc/doc/doc/doc/.../doc/doc/')
),
rparents(rpath) as (
    select reverse(trim(trailing '/' from path))
    from   path
  union all
    select trim(leading '/' from substring(rpath from p))
    from   rparents, position('/' in rpath) p
    where  p > 0
)
select reverse(rpath)
from   rparents

但遗憾的是,从结尾处搜索字符串是不可能的,因此需要多次调用reverse()函数来实现这种功能。

另一个解决方案是使用窗口函数:

with path(path) as (
  values ('d2140247-ef9d-4d51-ac28-ba008c378720//H%3A/files/doc/doc/doc/doc/.../doc/doc/')
)
select string_agg(unnest, '/') over (order by ordinality)
from   path, unnest(string_to_array(path, '/')) with ordinality
where  unnest != ''

注意with ordinality是9.4+功能,但您可以使用子选择row_number()进行模拟。

另外,如果你真的想得到一个父路径数组(而不是它们的结果集),你可以使用array_agg()(可能还有一个子选择)。

这两个功能都比plpgsql功能更好,但是如果你在问题中使用这么长的路径,由于IO,它们仍然会很慢。

编辑:一个版本,它将斜杠字符视为文件夹名称的一部分,后跟另一个斜杠:

with path(path) as (
  values ('d2140247-ef9d-4d51-ac28-ba008c378720//H%3A/files/doc///doc/doc/doc/.../doc/doc/')
)
select string_agg(regexp_split_to_table, '/') over (order by ordinality)
from   path, regexp_split_to_table(path, '/(?!/)') with ordinality
where  regexp_split_to_table != ''