我們在我們的rails項目中使用ancestry gem。表中有大約800個類別:遞歸postgres SQL優化
db => SELECT id, ancestry FROM product_categories LIMIT 10;
id | ancestry
-----+-------------
399 | 3
298 | 8/292/294
12 | 3/401/255
573 | 349/572
707 | 7/23/89/147
201 | 166/191
729 | 5/727
84 | 7/23
128 | 7/41/105
405 | 339
(10 rows)
ancestry
字段代表記錄的「路徑」。我需要的是建立一個地圖{CATEGORY_ID => [... all_subtree_ids ...]}
我解決了這個通過使用子查詢是這樣的:
SELECT id,
(
SELECT array_agg(id)
FROM product_categories
WHERE (ancestry LIKE CONCAT(p.id, '/%') OR
ancestry = CONCAT(p.ancestry, '/', p.id, '') OR
ancestry = (p.id) :: TEXT)
) categories
FROM product_categories p
ORDER BY id
導致
1 | {17,470,32,29,15,836,845,837}
2 | {37,233,231,205,107,109,57,108,28,58, ...}
但問題是這個查詢運行大約100ms,我不知道是否有一種方法來優化它使用WITH recursive
?我是新手,所以我的查詢只是掛postgres :(
** ========= UPD ========= ** 接受AlexM答案爲最快,但如果任何人有興趣,這裏的遞歸解決方案:
WITH RECURSIVE a AS
(SELECT id, id as parent_id FROM product_categories
UNION all
SELECT pc.id, a.parent_id FROM product_categories pc, a
WHERE regexp_replace(pc.ancestry, '^(\d{1,}/)*', '')::integer = a.id)
SELECT parent_id, sort(array_agg(id)) as children FROM a WHERE id <> parent_id group by parent_id order by parent_id;
真棒,謝謝 – Eugene