递归postgres SQL优化

时间:2017-04-20 09:34:37

标签: postgresql recursion optimization

我们在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

2 个答案:

答案 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)输出。