使用 PostGIS 查找最近点

Find nearest point using PostGIS

在带有 PostGIS 扩展的 PostgreSQL 12 上,我有两个表定义如下:

CREATE TABLE table_a (
    id_a integer,
    id_b integer,    
    coord geometry,
);

CREATE INDEX table_a_coord_idx ON table_a USING gist (coord);

CREATE TABLE table_b (
    id_b integer,
    coord geometry,
);

CREATE INDEX table_b_coord_idx ON table_b USING gist (coord);

两个表都有大约 300 万个条目。 coord 列仅包含点几何。 id_b 的值最初为空。

我的目标是为 table_a 中的每个点找到距离 table_b 最近的点并填写 id_b 列。 我写了一个小 Python 脚本来通过基于索引的 KNN 搜索来实现这一点:

import psycopg2 as pg

conn = pg.connect()
cur = conn.cursor()

cnt = 0
cur.execute('SELECT id_a, coord FROM table_a WHERE id_b IS NULL')
for row in cur.fetchall():
    cnt += 1
    cur.execute('SELECT id_b FROM table_b ORDER BY geom <-> %s LIMIT 1;', (row[1],))
    nearest_vertex = cur.fetchone()
    cur.execute('UPDATE table_a SET id_b=%s WHERE id_a=%s', (nearest_vertex[0], row[0]))
    if cnt % 1000 == 0:
        conn.commit()
conn.commit()

此代码有效。但是处理一个条目平均需要0.6s,因此处理所有条目需要大约三周的时间。

有人知道如何加快这个过程吗?

在一个循环中,1 条 1 条地处理记录,给数据库带来大量网络流量。
相反,尝试在一条语句中一次更新所有条目(如果您愿意,可以从 pyton 脚本发送)。

UPDATE table_a 
SET id_b = (
  SELECT id_b 
  FROM table_b 
  ORDER BY table_b.geom <-> table_a.geom 
  LIMIT 1
)
WHERE id_b IS NULL;

有点晚了,但我的第一个镜头是检查这样的查询:

-- Find the nearest hospital to each school
-- that is within 3000 units of the school.
SELECT DISTINCT ON (s.gid) s.gid, s.school_name, s.geom, h.hospital_name
    FROM schools s
        LEFT JOIN hospitals h ON ST_DWithin(s.the_geom, h.geom, 3000)
    ORDER BY s.gid, ST_Distance(s.geom, h.geom);

来自 postgis 手册 http://postgis.net/docs/manual-3.0/ST_DWithin.html。只要确保你在几何列上有索引并避免大半径。半径越大查询越慢