1

当谈到 PostgreSQL 时,我是一个菜鸟,但我能够让它产生我需要它做的事情,即采用高达 30 级深的层次结构,并创建一个扁平列表“锯齿状”列表视图每个终端节点的最高层和每个中间层。递归函数,只是将找到的每个父节点推入一个数组,然后使用 (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;
4

1 回答 1

1

您应该检查函数的volatile属性。

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

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

于 2013-09-23T07:54:50.870 回答