在postgres中以递归查询排序

时间:2017-07-11 21:13:17

标签: postgresql recursion

我有以下查询:

with recursive chain(id, weight, depth) as (
select rpCore.itemID2, rpCore.weight, 1 as depth from relations rpCore where itemID1 = 1048663
union 
select r.itemID2, c.weight + r.weight, c.depth + 1from chain c
inner join relations r
on (r.itemID1=id)
where c.depth < 3
order by c.weight + r.weight asc limit 10
) select * from chain order by weight asc limit 10;

如果我运行它,我会收到以下错误:

ERROR: ORDER BY in a recursive query is not implemented
SQL state: 0A000
Character: 313

由于权重的结构方式(所有正面,并且加在一起)如果我可以获得查询的递归部分来排序和限制自身,查询的外部部分将返回我需要的结果,但它似乎您无法在递归查询的递归部分执行订单。

有没有办法模拟这种行为?如果我删除了limit语句,那么查询就会运行,但是由于大量的(由于最终的限制语句而不必要的)行,它运行得非常慢。

1 个答案:

答案 0 :(得分:2)

正如我理解你的问题,你想为递归CTE关系添加一个LIMIT,以防止它递归过多的结果,这使查询变慢。

答案是你不能这样做。它不仅没有在PostgreSQL中实现;你所要求的东西在逻辑上是不可能的。

当PostgreSQL对每组相关记录进行递归时,它会累积一个事实上按深度排序的集合。这与您想要的顺序不同,这是一个不相关的列,&#34; weight&#34;。出于这个原因,Postgres没有办法根据权重限制而不累积完整的递归数据集 first 。因此,即使支持CTE中的ORDER BY语句,也不会改善您的表现。

我还要指出,在任何 UNION查询中,ORDER BY应用于结果数据集,到UNION的每个部分。因此,您无法将其应用于&#34;递归部分&#34;。

当然,您可以通过深度来提前终止递归,就像您在此查询中已经完成的那样。将UNION更改为UNION ALL也可以提高性能。

从语法上讲,你可以通过添加第二个CTE来实现你想要的东西:

  with recursive chain(id, weight, depth) as (
  select rpCore.itemID2, rpCore.weight, 1 as depth 
  from relations rpCore 
  where itemID1 = 1048663
  union all
  select r.itemID2, c.weight + r.weight, c.depth + 1
  from chain c
  inner join relations r
  on (r.itemID1=id)
  where c.depth < 3
  ),
  chain_limit as (
  SELECT * FROM chain
  ORDER BY weight LIMIT 10
  )
  select * from chain_limit;

然而,这不会帮助您实现绩效目标。

相关问题