我们在rails项目中使用ancestry gem。表中约有大约800个类别:
/getupdates
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)
字段表示记录的“路径”。我需要的是建立一个地图{category_id => [... all_subtree_ids ...]}
我通过使用这样的子查询来解决这个问题:
ancestry
导致
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
但问题是此查询运行大约100毫秒,我想知道是否有办法使用1 | {17,470,32,29,15,836,845,837}
2 | {37,233,231,205,107,109,57,108,28,58, ...}
对其进行优化?我是WITH的新手,所以我的查询只是挂了postgres :(
** ========= UPD ========= ** 接受AlexM回答最快,但如果有人感兴趣,这里是递归解决方案:
WITH recursive
答案 0 :(得分:1)
尝试这种方法,我认为它应该比嵌套查询快得多:
WITH product_categories_flat AS (
SELECT id, unnest(string_to_array(ancestry, '/')) as parent
FROM product_categories
)
SELECT parent as id, array_agg(id) as children
FROM product_categories_flat
GROUP BY parent
答案 1 :(得分:0)
可能性更快:
SELECT p1.id,
p2.array_agg(id)
FROM product_categories p
JOIN product_categories p2
ON p2.ancestry LIKE CONCAT(p1.id, '/%')
OR p2.ancestry = CONCAT(p1.ancestry, '/', p1.id)
OR p2.ancestry = p1.id::text)
GROUP BY p1.id
ORDER BY p1.id;
但要说清楚一点,你必须看EXPLAIN (ANALYZE, BUFFERS)
输出。