0

我遇到了输出 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 仅包含一个名为 content 类型的文本字段。内容的平均长度为 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)

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

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

服务器版本是 8.3.6 ......所以我没有可用的 xmlagg 函数

4

3 回答 3

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 ;
于 2012-12-04T09:23:24.120 回答
0

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

另一个原因可能是旧对象没有正确清理。这有时也是性能下降的原因,因为对文档的解析会创建大量临时对象。

XMLconcat 每次都可能解析所有参数。如果在处理代码时只存在上述问题之一,那么处理将变得越来越慢。

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

于 2012-12-04T13:25:07.937 回答
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
于 2019-11-06T15:22:54.480 回答