Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL有效地查找线性列表中的最后一个Decentant_Sql_Postgresql_Recursive Query - Fatal编程技术网

PostgreSQL有效地查找线性列表中的最后一个Decentant

PostgreSQL有效地查找线性列表中的最后一个Decentant,sql,postgresql,recursive-query,Sql,Postgresql,Recursive Query,目前,我试图从类似链表的结构中高效地检索最后一个decedet 本质上,有一个包含数据系列的表,根据某些条件,我将其拆分为如下列表 当前|下一个| id 比如说 1 | 2 2 | 3 3 | 4 4 | NULL 42 | 43 43 | 45 45 | NULL etc... 将产生如下列表 1->2->3->4 及 42->43->45 现在我想从每个列表中获取第一个和最后一个id 这就是我现在拥有的: WITH RECURSIVE contract(ruid, rdid, rs

目前,我试图从类似链表的结构中高效地检索最后一个decedet

本质上,有一个包含数据系列的表,根据某些条件,我将其拆分为如下列表

当前|下一个| id

比如说

1  | 2
2  | 3
3  | 4
4  | NULL
42 | 43
43 | 45
45 | NULL
etc...
将产生如下列表

1->2->3->4

42->43->45

现在我想从每个列表中获取第一个和最后一个id

这就是我现在拥有的:

WITH RECURSIVE contract(ruid, rdid, rstart_ts, rend_ts) AS ( -- recursive Query to traverse the "linked list" of continuous timestamps
    SELECT start_ts, end_ts FROM track_caps tc
    UNION
    SELECT c.rstart_ts, tc.end_ts AS end_ts0 FROM contract c INNER JOIN track_caps tc ON (tc.start_ts = c.rend_ts AND c.rend_ts IS NOT NULL AND tc.end_ts IS NOT NULL)
),
fcontract AS ( --final step, after traversing the "linked list", pick the largest timestamp found as the end_ts and the smallest as the start_ts
    SELECT DISTINCT ON(start_ts, end_ts) min(rstart_ts) AS start_ts, rend_ts AS end_ts
    FROM (
        SELECT rstart_ts, max(rend_ts) AS rend_ts FROM contract
        GROUP BY rstart_ts
    ) sq
    GROUP BY end_ts
)
SELECT * FROM fcontract
ORDER BY start_ts
在本例中,我只使用了时间戳,对于给定的数据,时间戳可以很好地工作

基本上,我只是使用一个递归查询,遍历所有节点,直到到达末尾,正如StackOverflow和其他站点上的许多其他帖子所建议的那样。下一个查询将删除所有子步骤并返回所需内容,如第一个列表示例:1 | 4

仅用于说明,递归查询生成的结果集如下所示:

1  | 2
2  | 3
3  | 4
1  | 3
2  | 4
1  | 4
with recursive contract as (
  select t1.current_id, t1.next_id, t1.current_id as root_id
  from track_caps t1
  where not exists (select * 
                    from track_caps t2
                    where t2.next_id = t1.current_id)
  union 
  select c.current_id, c.next_id, p.root_id
  from track_caps c
    join contract p on c.current_id = p.next_id
  and c.next_id is not null
)
select *
from contract
order by current_id;
尽管它工作得很好,但它相当占用内存,这在查看
EXPLAIN ANALYZE
的结果时绝对不令人惊讶。 对于大约42600行的数据集,递归查询生成的行数高达849542346行。现在它实际上应该处理大约2000000行,但是现在这个解决方案似乎非常不可行

我只是不正确地使用了递归查询吗?有没有办法减少它产生的数据量?(比如删除子步骤?)
或者有更好的单查询解决方案来解决这个问题吗?

主要问题是递归查询没有正确过滤根节点,这是由模型引起的。因此,非递归部分已经选择了整个表,然后Postgres需要对表中的每一行进行递归

为了提高效率,只需在查询的非递归部分选择根节点。这可以通过以下方式实现:

select t1.current_id, t1.next_id, t1.current_id as root_id
from track_caps t1
where not exists (select * 
                  from track_caps t2
                  where t2.next_id = t1.current_id)
现在这仍然不是很有效(与“通常”的父id为null的设计相比),但至少确保递归不需要处理更多的行

要找到每棵树的根节点,只需在查询的非递归部分中选择它作为一个额外的列,并将其传递到递归部分的每一行

所以你会得到这样的结果:

1  | 2
2  | 3
3  | 4
1  | 3
2  | 4
1  | 4
with recursive contract as (
  select t1.current_id, t1.next_id, t1.current_id as root_id
  from track_caps t1
  where not exists (select * 
                    from track_caps t2
                    where t2.next_id = t1.current_id)
  union 
  select c.current_id, c.next_id, p.root_id
  from track_caps c
    join contract p on c.current_id = p.next_id
  and c.next_id is not null
)
select *
from contract
order by current_id;

在线示例:

也许我遗漏了一些东西,但这不是简单的
下一个\u id不为null的地方吗?@a\u horse\u,没有\u名称,但是我如何获得列表的第一个id,它属于使用where子句选择的最后一个id?不错,它将行数减少了一半。但你提到了另一个“设计”。我不也会面临同样的问题吗?在那里,我很容易得到第一个节点,而不得不搜索最后一个节点。这里我有相反的。获取最后一个节点很容易,但从某种意义上说,我必须浏览第一个节点的列表。