下面的查询需要将近 15 分钟的时间才能显示结果。我想知道为什么?因为数据?还是几何体的顶点?当我尝试使用不同的表(小型 shapefile)进行查询时,它运行得很快。
这是查询。 (为此感谢 Patrick):
WITH hi AS (
SELECT ps.id, ps.brgy_locat, ps.municipali
FROM evidensapp_polystructures ps
JOIN evidensapp_seniangcbr fh ON fh.hazard = 'High'
AND ST_Intersects(fh.geom, ps.geom)
), med AS (
SELECT ps.id, ps.brgy_locat, ps.municipali
FROM evidensapp_polystructures ps
JOIN evidensapp_seniangcbr fh ON fh.hazard = 'Medium'
AND ST_Intersects(fh.geom, ps.geom)
EXCEPT SELECT * FROM hi
), low AS (
SELECT ps.id, ps.brgy_locat, ps.municipali
FROM evidensapp_polystructures ps
JOIN evidensapp_seniangcbr fh ON fh.hazard = 'Low'
AND ST_Intersects(fh.geom, ps.geom)
EXCEPT SELECT * FROM hi
EXCEPT SELECT * FROM med
)
SELECT brgy_locat AS barangay, municipali AS municipality, high, medium, low
FROM (SELECT brgy_locat, municipali, count(*) AS high
FROM hi
GROUP BY 1, 2) cnt_hi
FULL JOIN (SELECT brgy_locat, municipali, count(*) AS medium
FROM med
GROUP BY 1, 2) cnt_med USING (brgy_locat, municipali)
FULL JOIN (SELECT brgy_locat, municipali, count(*) AS low
FROM low
GROUP BY 1, 2) cnt_low USING (brgy_locat, municipali);
PostgreSQL 9.3、PostGIS 2.1.5
表 Polystructures
:包含 9847 行:
CREATE TABLE evidensapp_polystructures (
id serial NOT NULL PRIMARY KEY,
bldg_name character varying(100) NOT NULL,
bldg_type character varying(50) NOT NULL,
brgy_locat character varying(50) NOT NULL,
municipali character varying(50) NOT NULL,
province character varying(50) NOT NULL,
geom geometry(MultiPolygon,32651)
);
CREATE INDEX evidensapp_polystructures_geom_id
ON evidensapp_polystructures USING gist (geom);
ALTER TABLE evidensapp_polystructures CLUSTER ON evidensapp_polystructures_geom_id;
表 SeniangCBR
:只有 6 行,shapefile 大小(如果重要的话):52,060 KB
CREATE TABLE evidensapp_seniangcbr (
id serial NOT NULL PRIMARY KEY,
hazard character varying(16) NOT NULL,
geom geometry(MultiPolygon,32651)
);
CREATE INDEX evidensapp_seniangcbr_geom_id ON evidensapp_seniangcbr USING gist (geom);
ALTER TABLE evidensapp_seniangcbr CLUSTER ON evidensapp_seniangcbr_geom_id;
使用LayerMapping 自动将所有数据加载到数据库中我正在使用的实用程序 Django(GeoDjango) .
我现在没有服务器,我在我的电脑上运行查询。
- 处理器:Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz(8 个 CPU),~3.6GHz
- 内存:8192MB RAM
- 操作系统:Windows 7 64 位
最佳答案
EXPLAIN ANALYZE
输出很难阅读,因为所有字段和函数都被打乱到 radio alphabet 中.也就是说,有两点很突出:
- 大部分时间花在
ST_Intersects()
函数上,这不足为奇。 EXCEPT
子句似乎也相当低效。
所以请尝试这个更简洁的版本:
SELECT brgy_locat AS barangay, municipali AS municipality,
sum(CASE max_hz_id WHEN 3 THEN 1 ELSE 0 END) AS high,
sum(CASE max_hz_id WHEN 2 THEN 1 ELSE 0 END) AS medium,
sum(CASE max_hz_id WHEN 1 THEN 1 ELSE 0 END) AS low
FROM (
SELECT ps.id, ps.brgy_locat, ps.municipali,
max(CASE fh.hazard WHEN 'Low' THEN 1 WHEN 'Medium' THEN 2 WHEN 'High' THEN 3 END) AS max_hz_id
FROM evidensapp_polystructures ps
JOIN evidensapp_seniangcbr fh ON ST_Intersects(fh.geom, ps.geom)
GROUP BY 1, 2, 3
) AS ps_fh
GROUP BY 1, 2;
现在只有一次对 ST_Intersects()
的调用,这可能(希望)比对危险 map 子集的三个调用快很多(由于 PostGIS 的内部效率代码)。
很明显,危险类别字符串被转换为整数范围,以便于排序和比较。在内部查询中,根据您的要求选择最大危险值。在主查询中,每个结构的那些最大值被汇总到它们各自的列中。如果可能的话,更改您的表结构以使用这三个整数代码并链接到类标签的帮助表:您的表会变得更小,因此更快,并且内部查询中的 CASE
语句可以被丢弃。或者,添加一个包含整数代码的列,并根据“危险”列更新值。
请注意,这些 CASE
语句不是很有效(我在上一个答案中使用 EXCEPT
子句的原因)。在 PG 9.4 中,引入了一个关于聚合函数的新 FILTER
子句,这将使查询更快且更易于阅读:
count(id) FILTER (WHERE max_hz_id = 3) AS high
您可能需要考虑升级。
拉马特穆拉梅尼拉
关于django - 在 PostgreSQL(PostGIS) 中优化 ST_Intersects,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31799824/