PostgreSQL递归查询性能

时间:2013-09-23 01:26:06

标签: postgresql recursion

对于PostgreSQL来说,我是一个菜鸟,但是我能够让它产生我需要它做的事情,即采用最高达30级的层次结构,并创建一个扁平的列表'锯齿' listview具有每个端节点的最高级别和每个中间级别。递归函数,只是将找到的每个父项推送到一个数组中,然后使用(LIMIT 1)

返回每个节点的最终展平列表

以下SQL部分生成我需要的表。我的问题是我的函数返回我使用的值数组填充行列是每行调用一次,还是每行30列中的每一列调用一次。

有人可以指导我如何确定吗?和/或如果显然我的SQL效率低下,那么将这些语句放在一起可能是更好的方法。

提前感谢您的光临。

DROP FUNCTION IF EXISTS fnctreepath(nodeid NUMERIC(10,0));

CREATE FUNCTION fnctreepath(nodeid NUMERIC(10,0)) 
        RETURNS TABLE (endnode NUMERIC, depth INTEGER, path NUMERIC[]) AS
$$ 
WITH RECURSIVE ttbltreepath(endnode, nodeid, parentid, depth, path) AS (
   SELECT src.nodeid AS endnode, src.nodeid, src.parentid, 1::INT AS depth, 
                 ARRAY[src.nodeid::NUMERIC(10,0)]::NUMERIC(10,0)[] AS path 
      FROM tree AS src WHERE nodeid = $1
UNION
   SELECT ttbl.endnode, src.nodeid, src.parentid, ttbl.depth + 1 AS depth, 
                 ARRAY_PREPEND(src.nodeid::NUMERIC(10,0), ttbl.path::NUMERIC(10,0)[])::NUMERIC(10,0)[] AS path 
      FROM tree AS src, ttbltreepath AS ttbl WHERE ttbl.parentid = src.nodeid
)
SELECT endnode, depth, path FROM ttbltreepath GROUP BY endnode, depth, path ORDER BY endnode, depth DESC LIMIT 1;
$$ LANGUAGE SQL;

DROP TABLE IF EXISTS treepath;

SELECT parentid, nodeid, name
        (fnctreepath(tree.nodeid)).depth, 
               (fnctreepath(tree.nodeid)).path[1] as nodeid01, 
                (fnctreepath(tree.nodeid)).path[2] as nodeid02,
                (fnctreepath(tree.nodeid)).path[3] as nodeid03,
                (fnctreepath(tree.nodeid)).path[4] as nodeid04,
                (fnctreepath(tree.nodeid)).path[5] as nodeid05,
                (fnctreepath(tree.nodeid)).path[6] as nodeid06,
                (fnctreepath(tree.nodeid)).path[7] as nodeid07,
                (fnctreepath(tree.nodeid)).path[8] as nodeid08,
                (fnctreepath(tree.nodeid)).path[9] as nodeid09,
                (fnctreepath(tree.nodeid)).path[10] as nodeid10,
                (fnctreepath(tree.nodeid)).path[11] as nodeid11,
                (fnctreepath(tree.nodeid)).path[12] as nodeid12,
                (fnctreepath(tree.nodeid)).path[13] as nodeid13,
                (fnctreepath(tree.nodeid)).path[14] as nodeid14,
                (fnctreepath(tree.nodeid)).path[15] as nodeid15,
                (fnctreepath(tree.nodeid)).path[16] as nodeid16,
                (fnctreepath(tree.nodeid)).path[17] as nodeid17,
                (fnctreepath(tree.nodeid)).path[18] as nodeid18,
                (fnctreepath(tree.nodeid)).path[19] as nodeid19,
                (fnctreepath(tree.nodeid)).path[20] as nodeid20,
                (fnctreepath(tree.nodeid)).path[21] as nodeid21,
                (fnctreepath(tree.nodeid)).path[22] as nodeid22,
                (fnctreepath(tree.nodeid)).path[23] as nodeid23,
                (fnctreepath(tree.nodeid)).path[24] as nodeid24,
                (fnctreepath(tree.nodeid)).path[25] as nodeid25,
                (fnctreepath(tree.nodeid)).path[26] as nodeid26,
                (fnctreepath(tree.nodeid)).path[27] as nodeid27,
                (fnctreepath(tree.nodeid)).path[28] as nodeid28,
                (fnctreepath(tree.nodeid)).path[29] as nodeid29,
                (fnctreepath(tree.nodeid)).path[30] as nodeid30
INTO treepath
FROM tree;

1 个答案:

答案 0 :(得分:1)

您应该检查功能的volatile属性。

默认一个函数是 VOLATILE ,这意味着对该函数的任何调用都可能会改变数据库,因此当您多次使用该函数时,查询优化器无法重用该结果在同一声明中。

您的功能不是 IMUTABLE 2+2=4是不可变的。但是你应该为你的函数定义 STABLE volatility关键字,这样优化者可以重用你在同一语句中多次使用fnctreepath(tree.nodeid)的调用作为稳定的结果并共享它(运行它)只有一次。