SQLite中使用WITH子句更新PostGIS属性表within_area字段时查询无响应问题求助
嘿,你这明显是踩了笛卡尔积+重复计算的坑了!原来的SELECT能跑10秒,但改成UPDATE就卡住,核心原因是你的更新写法让数据库做了大量完全没必要的重复工作,咱们一步步捋清楚:
先搞懂你的原始查询问题
你原来的SELECT语句:
select properties.id, ST_Within(properties.geoarea,st_transform("urbanArea"."st_union",2393)) from properties,"urbanArea"
这里用了properties,"urbanArea"的隐式交叉连接(笛卡尔积)——如果urbanArea有N条记录,properties有M条,这条查询会返回M×N条记录!
我猜你其实是想让每个点和urbanArea整个表的合并多边形做判断?(比如urbanArea的st_union是整个区域的聚合结果?)如果是这样,你的原始SELECT其实已经在做重复计算了,只不过数据量还没大到卡住,但改成UPDATE后,这个问题被放大了N倍。
为什么你的UPDATE会卡住?
咱们看你第一个UPDATE写法:
UPDATE properties p SET within_area = ( with newarea as (select properties.id, ST_Within(properties.geoarea,st_transform("urbanArea"."st_union",2393)) as "isInside" from properties,"urbanArea") select u."isInside" from newarea u where u.id = p.id )
这里的问题是:每更新一条properties记录,都会重新执行一遍newarea这个CTE——也就是每次更新一行,都要生成M×N条记录的临时表,再筛选出当前id的结果。假设你有1万条properties、100条urbanArea,那每次更新就要处理100万条数据,1万次更新就是100亿条的计算量,不卡住才怪!
第二个UPDATE写法也一样:CTE里还是生成了M×N条笛卡尔积记录,然后关联时又重复匹配,不仅计算量爆炸,还可能出现同一行被多次更新的问题。
正确的写法应该这样
核心思路:只计算一次urbanArea的合并转换多边形,然后一次性和所有properties记录做关联判断。
情况1:urbanArea的合并多边形需要实时计算
如果urbanArea里是分散的多边形,需要先聚合整个区域的union,那用这个写法:
WITH urban_union AS ( -- 先一次性计算出整个urbanArea的合并多边形,并转换到2393坐标系 SELECT st_transform(st_union(geom), 2393) AS union_geom FROM "urbanArea" -- 这里把geom改成你urbanArea表实际的几何列名 ) UPDATE properties p SET within_area = ST_Within(p.geoarea, uu.union_geom) FROM urban_union uu;
情况2:urbanArea表已经存了预计算好的整个区域union(只有1条记录)
如果你的urbanArea表本身就只有一条记录,存的是整个区域的st_union结果,那直接关联一次就好:
UPDATE properties p SET within_area = ST_Within(p.geoarea, st_transform(ua."st_union", 2393)) FROM "urbanArea" ua;
这个写法只会把每个properties记录和唯一的union多边形做一次判断,没有笛卡尔积,计算量和你原来的SELECT差不多,很快就能跑完。
额外优化建议
- 给
properties.geoarea加空间索引,能大幅加快ST_Within的判断速度:
CREATE INDEX idx_properties_geoarea ON properties USING GIST (geoarea);
- 如果这个urban区域的union是经常要用的,建议把它存成一个单独的表或者物化视图,避免每次都重复计算st_union和st_transform。
内容的提问来源于stack exchange,提问作者BitByte

