Postgresql xmlconcat很慢

时间:2012-12-04 09:03:14

标签: xml performance postgresql plpgsql

输出xml的PL / PGsql存储过程出了问题。

基本上,函数输出为xml查询结果。

查询速度足够快,但我发现当结果集太大时,xmlconcat变得越来越慢。

这是该功能的简化内容。

CREATE OR REPLACE FUNCTION test_function (v_limit int)
    RETURNS xml AS
$BODY$
DECLARE
    v_rec record;
    v_xml xml;
    v_query text;
BEGIN

    v_query := 'SELECT * FROM test_table LIMIT ' || v_limit;

    FOR v_rec IN EXECUTE v_query LOOP

        v_xml := xmlconcat(v_xml,
                     xmlelement(name content, v_rec.content)
                 );

    END LOOP;

    RETURN v_xml ;
END
$BODY$
    LANGUAGE 'plpgsql' SECURITY DEFINER ;

表test_table只包含一个名为text类型的内容的字段。内容的平均长度为100个字符。

问题出现时会有大量记录要连接。

看看这个解释分析。所需时间呈指数级增长。

db=# explain analyze select test_function(500);
                                      QUERY PLAN
--------------------------------------------------------------------------------------
 Result  (cost=0.00..0.26 rows=1 width=0) (actual time=42.890..42.893 rows=1 loops=1)
 Total runtime: 42.909 ms
(2 rows)


db=# explain analyze select test_function(1000);
                                       QUERY PLAN
----------------------------------------------------------------------------------------
 Result  (cost=0.00..0.26 rows=1 width=0) (actual time=109.153..109.159 rows=1 loops=1)
 Total runtime: 109.178 ms
(2 rows)

db=# explain analyze select test_function(10000);
                                        QUERY PLAN
------------------------------------------------------------------------------------------
 Result  (cost=0.00..0.26 rows=1 width=0) (actual time=8304.257..8304.277 rows=1 loops=1)
 Total runtime: 8304.298 ms
(2 rows)

没有xmlconcat的单个查询的成本对于10000条记录只有36毫秒。

有关提高xmlconcat效率的任何建议吗?

服务器版本是8.3.6 ...所以我没有xmlagg功能可用

3 个答案:

答案 0 :(得分:0)

尝试测试此功能:

CREATE OR REPLACE FUNCTION test_function (v_limit int)
    RETURNS xml AS
$BODY$
BEGIN
    RETURN SELECT xmlagg(xmlelement(name content, tt.content))
           FROM test_table tt 
           LIMIT v_limit;
END
$BODY$
    LANGUAGE 'plpgsql' SECURITY DEFINER ;

答案 1 :(得分:0)

我经常使用XML看到这种内存问题。这通常与DOMparser的使用有关。 DOMparser将完整的文档保存在内存中,当您想要集中处理文档时非常方便。

另一个原因可能是旧物体未正确清理。这有时也是降低性能的原因,因为解析文档会产生大量临时对象。

每次XMLconcat都可以解析所有参数。如果在处理代码时确实只存在上述问题中的一个,则处理将变得越来越慢。

我猜是不可能理解导致这些问题的原因,然后深入研究xmlconcat的代码 - Peter Eisentraut可能知道。但你唯一需要的是连接一组xmlelements。使用xmlconcat可能会超过顶部,因为它对于可能可预测的情况来说太复杂了。我建议你停止使用xmlconcat并开始自己编写连接。可能是同时最快,最合适的解决方案。

答案 2 :(得分:0)

postgresql 11具有与xmlagg相同的性能差,但是可以很容易地用string_agg代替。一些测试:

select xmlagg(xmlelement(name "id", s.id)) el
from generate_series(1, 10000) s(id)
- Execution Time: 131.849 ms

select xmlagg(xmlelement(name "id", s.id)) el
from generate_series(1, 20000) s(id)
- Execution Time: 623.741 ms

select xmlagg(xmlelement(name "id", s.id)) el
from generate_series(1, 30000) s(id)
- Execution Time: 1571.545 ms

select string_agg(xmlelement(name "id", s.id)::text, '')::xml el
from generate_series(1, 10000) s(id)
- Execution Time: 38.743 ms

select string_agg(xmlelement(name "id", s.id)::text, '')::xml el
from generate_series(1, 20000) s(id)
- Execution Time: 54.399 ms

select string_agg(xmlelement(name "id", s.id)::text, '')::xml el
from generate_series(1, 30000) s(id)
- Execution Time: 91.766 ms