1

私は PostgreSQL に関しては初心者ですが、最大 30 レベルの深さの階層を取得し、フラット化されたリストの「ギザギザ」リストビューを作成するために必要なことを生成することができました。の最上位レベルおよび各エンド ノードまでのすべての介在レベル。再帰関数は、見つかったすべての親を配列にプッシュし、(LIMIT 1) を使用して各ノードの最終的な平坦化されたリストを返します。

次の SQL は、必要なテーブルを生成します。私の質問は、行列に入力する値の配列を返す関数が行ごとに 1 回呼び出されるのか、それとも各行の 30 列ごとに 1 回呼び出されるのかということです。

誰かが私がそれをどのように判断するかを教えてもらえますか? そして/または私の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 ですつまり、関数を呼び出すとデータベースが変更される可能性があるため、同じステートメントで関数を複数回使用した場合、クエリ オプティマイザは結果を再利用できません。

あなたの関数はIMUTABLEではなく、2+2=4不変です。ただし、関数にSTABLE volatility キーワードを定義する必要があります。これにより、オプティマイザーはfnctreepath(tree.nodeid)、安定した結果として同じステートメントで used の呼び出しを数回再利用し、それを共有できます (一度だけ実行します)。

于 2013-09-23T07:54:50.870 に答える