【问题标题】:PostgreSQL - Calculate the minimum distance between two pointsPostgreSQL - 计算两点之间的最小距离
【发布时间】:2020-04-02 20:50:00
【问题描述】:

我有一个相当大的点层(刚刚超过 100 万),我想选择将同一层的每个点与另一个点(最近的邻居)分开的最短距离。在网上查了一些资料后,翻到了Cross Join Lateral子句。

但是,请求永远不会结束(超过 5 小时未完成)。我与 QGis 距离矩阵进行了比较,那里的计算时间似乎要快得多(大约每 5 分钟 10%)。我告诉自己,原因可能在于表述不当。

这是我使用的代码:

with couche_points as (select * from public.centroides_batis_all)
select p.id, t.id_2, t.dist
from couche_points p cross join lateral(
select r.id as id_2, p.geom <-> r.geom as dist
from couche_points r
where p.id <> r.id
order by p.geom <-> r.geom
limit 1) as t

但是,我觉得一切都很好。 PostGis 和 QGis 的性能有区别吗?

谢谢。

【问题讨论】:

    标签: postgresql distance qgis


    【解决方案1】:

    虚拟 CTE 的意义何在?它所做的只是破坏了真实表上任何索引的使用(这无疑是对缓慢的充分解释)

    select p.id, t.id_2, t.dist
    from centroides_batis_all p cross join lateral(
    select r.id as id_2, p.geom <-> r.geom as dist
    from centroides_batis_all r
    where p.id <> r.id
    order by p.geom <-> r.geom
    limit 1) as t;
    

    【讨论】:

      【解决方案2】:

      正如我所见,您正在查询中构建这样的矩阵:

      p1 p2 p3 p4 ... pn p1 -​​-- d21 d31 d41 ... dn1 p2 d12 --- d32 d42 ... dn2 p3 d13 d23 --- d43 ... dn3 p4 d14 d24 d34 --- ... dn4 ………………………………………………………………………………………… pn d1n d2n d3n d4n ... ---

      但实际上你只需要它的一半,因为左下半部分只是重复了右上角的点交换:

      p1 p2 p3 p4 ... pn p1 -​​-- d21 d31 d41 ... dn1 p2 --- --- d32 d42 ... dn2 p3 --- --- --- d43 ... dn3 p4 --- --- --- --- ... dn4 …………………………………………………………………………………………………… pn --- --- --- --- ... ---
      select t1.id as id, t2.id as id_2, t2.dist
      from
        centroides_batis_all as t1 cross join lateral (
          select t2.id, t1.geom <-> t2.geom as dist
          from centroides_batis_all as t2 where t1.id < t2.id -- the main difference here
          order by dist limit 1) as t2;
      

      此查询将返回 p1-p2 等对,但不返回 p2-p1(当然距离相同)

      要解决此问题,您可以使用交换点复制上一个查询中的行:

      with cte as (
        select t1.id as id, t2.id as id_2, t2.dist
        from
          centroides_batis_all as t1 cross join lateral (
            select t2.id, t1.geom <-> t2.geom as dist
            from centroides_batis_all as t2 where t1.id < t2.id
            order by dist limit 1) as t2)
      select
        case t.n when 1 then cte.id else cte.id_2 end as id,
        case t.n when 1 then cte.id_2 else cte.id end as id_2,
        cte.dist
      from cte, (values(1), (2)) as t(n);
      

      【讨论】:

        【解决方案3】:

        也许您可以选择将您的积分分为四个方面。

        1.000.000 点的距离矩阵需要 1.000.000 x 1.000.000 = 1.000.000.000.000 次计算。

        4 个 250.000 点的距离矩阵需要 250.000 x 250.000 = 250.000.000.0000 次计算。

        这只是计算的 1/4。当然,您必须展示如何处理分割区域的组合,但它似乎要快得多。

        【讨论】:

          猜你喜欢
          • 2014-01-28
          • 2010-10-30
          • 2019-02-26
          • 2018-05-21
          • 2014-02-13
          • 2011-04-23
          相关资源
          最近更新 更多