Tôi cần tính toán độ sâu của một hậu duệ từ tổ tiên của nó. Khi một bản ghi có object_id = parent_id = ancestor_id
, nó được coi là một nút gốc (tổ tiên). Tôi đã cố gắng để có được một WITH RECURSIVE
truy vấn chạy với PostgreSQL 9.4 .
Tôi không kiểm soát dữ liệu hoặc các cột. Các lược đồ dữ liệu và bảng đến từ một nguồn bên ngoài. Bảng đang phát triển liên tục . Ngay bây giờ bằng khoảng 30k hồ sơ mỗi ngày. Bất kỳ nút nào trong cây có thể bị thiếu và chúng sẽ được kéo từ một nguồn bên ngoài tại một số điểm. Chúng thường được kéo theo created_at DESC
thứ tự nhưng dữ liệu được kéo với các công việc nền không đồng bộ.
Chúng tôi ban đầu đã có một giải pháp mã cho vấn đề này, nhưng bây giờ có hàng 5M +, phải mất gần 30 phút để hoàn thành.
Định nghĩa bảng ví dụ và dữ liệu thử nghiệm:
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 2
Lưu ý rằng object_id
không phải là duy nhất, nhưng sự kết hợp (customer_id, object_id)
là duy nhất.
Chạy một truy vấn như thế này:
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;
Tôi muốn generation
cột được đặt là độ sâu đã được tính toán. Khi một bản ghi mới được thêm vào, cột thế hệ được đặt là -1. Có một số trường hợp parent_id
có thể chưa được kéo. Nếu parent_id
không tồn tại, nó sẽ để cột thế hệ được đặt thành -1.
Dữ liệu cuối cùng sẽ trông như sau:
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
Kết quả của truy vấn sẽ là cập nhật cột tạo đến độ sâu chính xác.
Tôi bắt đầu làm việc từ các câu trả lời cho câu hỏi liên quan này trên SO .
update
bảng với kết quả của CTE đệ quy của bạn?