输出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功能可用
答案 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