祖先の子孫の深さを計算する必要があります。レコードにがある場合、レコードはobject_id = parent_id = ancestor_idルートノード(祖先)と見なされます。WITH RECURSIVEPostgreSQL 9.4でクエリを実行しようとしています。
データや列を制御しません。データおよびテーブルスキーマは外部ソースから取得されます。テーブルは継続的に成長しています。現在、1日あたり約3万件の記録があります。ツリー内のノードは欠落している可能性があり、ある時点で外部ソースからプルされます。彼らは通常引き込まれますcreated_at DESC順番にますが、データは非同期のバックグラウンドジョブでプルされます。
最初はこの問題に対するコードソリューションがありましたが、現在は500万行以上あり、完了するまでに約30分かかります。
テーブル定義とテストデータの例:
CREATE TABLE objects (
  id          serial NOT NULL PRIMARY KEY,
  customer_id integer NOT NULL,
  object_id   integer NOT NULL,
  parent_id   integer,
  ancestor_id integer,
  generation  integer NOT NULL DEFAULT 0
);
INSERT INTO objects(id, customer_id , object_id, parent_id, ancestor_id, generation)
VALUES (2, 1, 2, 1, 1, -1), --no parent yet
       (3, 2, 3, 3, 3, -1), --root node
       (4, 2, 4, 3, 3, -1), --depth 1
       (5, 2, 5, 4, 3, -1), --depth 2
       (6, 2, 6, 5, 3, -1), --depth 3
       (7, 1, 7, 7, 7, -1), --root node
       (8, 1, 8, 7, 7, -1), --depth 1
       (9, 1, 9, 8, 7, -1); --depth 2object_idは一意ではありませんが、組み合わせ(customer_id, object_id)は一意であることに注意してください。
次のようなクエリを実行します。
WITH RECURSIVE descendants(id, customer_id, object_id, parent_id, ancestor_id, depth) AS (
  SELECT id, customer_id, object_id, parent_id, ancestor_id, 0
  FROM objects
  WHERE object_id = parent_id
  UNION
  SELECT o.id, o.customer_id, o.object_id, o.parent_id, o.ancestor_id, d.depth + 1
  FROM objects o
  INNER JOIN descendants d ON d.parent_id = o.object_id
  WHERE
    d.id <> o.id
  AND
    d.customer_id = o.customer_id
) SELECT * FROM descendants d;generation計算された深さとして列を設定したいと思います。新しいレコードが追加されると、生成列は-1に設定されます。parent_idがまだプルされていない場合があります。もしparent_idが存在しない、生成列を-1のままにしておく必要があります。
最終データは次のようになります。
id | customer_id | object_id | parent_id | ancestor_id | generation
2    1             2           1           1            -1
3    2             3           3           3             0
4    2             4           3           3             1
5    2             5           4           3             2
6    2             6           5           3             3
7    1             7           7           7             0
8    1             8           7           7             1
9    1             9           8           7             2クエリの結果は、生成列を正しい深さに更新することです。
SOに関するこの関連する質問への回答から作業を始めました。
update再帰CTEの結果を表にしたいですか?