PostgreSQL - 根据ID从多行创建和连接数组

时间:2014-03-30 06:42:05

标签: arrays postgresql

我有两张桌子:

LINKS 有:

LINK_ID --- integer, unique ID
FROM_NODE_X -- numbers/floats, indicating a geographical position
FROM_NODE_Y --
FROM_NODE_Z --
TO_NODE_X --
TO_NODE_Y --
TO_NODE_Z --

LINK_COORDS 有:

LINK_ID --- integer, refers to above UID
ORDER --- integer, indicating order
X ---
Y ---
Z ---

逻辑上,每个 LINK 都包含多个航点。最后的订单是:

FROM_NODE , 1 , 2 , 3 , ... , TO_NODE

链接至少有两个航路点(FROM_NODE,TO_NODE),但两者之间可以有可变数量的航点(0到100 +)。

我现在需要一种方法来聚合,排序和存储数组中每个链接的航点,这些航点稍后将用于绘制线。

我正在努力将LINK_COORDS作为单独的行提供。将开始和结束位置放在另一个(LINKS)表中也没有帮助。如果我有办法让所有LINK_COORDS加入/更新到LINKS表,我可能会再次自己解决剩下的问题。因此,如果您对如何实现这一目标有所了解,那么我们已经非常感激。

考虑到性能会很好(表格现在介于500k到1mio之间,之后会有倍数),但现在不是必需的。

修改: 谢谢你的建议,一个没有名字的马。 我选择在此步骤之前为每个XYZ创建点几何(PostGIS),因此最终只能从各个点创建一个点阵列。 改编的SQL

UPDATE "Link"
SET "POINTS" = 
    array_append(
        (array_prepend(
            "FROM_POINT",
            (SELECT array_agg(lc."POINT" ORDER BY lc."COUNT")
                FROM "LinkCoordinate" lc 
                WHERE lc."LINK_ID" = "Link"."LINK_ID")))
        , "TO_POINT")

但运行速度极慢: 在10个链接上运行它需要~120秒。为所有1,3个米连杆和更多的连接线运行它可能需要大约半年的时间。不太理想。

我怎样才能弄清楚这种巨大的缓慢来自何处?

如果我以预先订购的格式获取源数据(因此每个link_ID的链接协调),这是否可以显着加快SQL查询的速度?

编辑:主要的减速似乎来自array_agg()函数中使用的SELECT子查询。其他一切(包括订购)并没有真正导致任何减速。

我目前的猜测是SELECT查询遍历整个" LinkCoordinate"对于每个链接,使其工作比以前更难,因为属于链接的所有LinkCoordinates 始终存储在'块'的行。实际上,LinkCoordinates的单个顺序处理就足够了。

1 个答案:

答案 0 :(得分:0)

这样的事情可能是:

select l.link_id, 
       min(l.from_node_x) as from_node_x, 
       min(l.from_node_y) as from_node_y, 
       min(l.from_node_z) as from_node_z,
       array_agg(lc.x order by lc."ORDER") as points_x,
       array_agg(lc.y order by lc."ORDER") as points_y,
       array_agg(lc.z order by lc."ORDER") as points_z,
       min(l.to_node_x) as to_node_x, 
       min(l.to_node_y) as to_node_y, 
       min(l.to_node_z) as to_node_z
from links l 
  join link_coords lc on lc.link_id = l.link_id
group by l.link_id;

由于min() group by是必要的,但由于links的所有值都相同,因此无法更改结果。

另一种可能性是使用标量子查询。我不确定哪一个更快 - 但加入/分组可能更有效。

select l.link_id, 
       l.from_node_x, 
       l.from_node_y, 
       l.from_node_z,
       (select array_agg(lc.x order by lc."ORDER") from link_coords lc where lc.link_id = l.link_id) as points_x,
       (select array_agg(lc.y order by lc."ORDER") from link_coords lc where lc.link_id = l.link_id) as points_y,
       (select array_agg(lc.z order by lc."ORDER") from link_coords lc where lc.link_id = l.link_id) as points_z,
       l.to_node_x, 
       l.to_node_y, 
       l.to_node_z
from links l