是否有可能强制Postgres规划器根据标量值的顺序扫描过滤结果集,然后才能根据空间索引执行GIS功能/比较?我的生产用例有点复杂,但这个例子说明了我的目标:
在该列上创建一个包含地理列和索引的表:
CREATE TABLE test_table (
id SERIAL,
min INTEGER,
max INTEGER,
active BOOLEAN,
geo GEOGRAPHY(Polygon,4326) );
CREATE INDEX test_table_gidx ON test_table USING gist (geo);
我使用非平凡的多边形几何(每个约10k个顶点)将6000个记录播种到表中。
根据min
和max
执行简单选择需要毫秒级。
geotest=> SELECT count(*) FROM test_table t WHERE t.min <= 50 AND t.max >= 50 ;
count
-------
4000
(1 row)
Time: 3.066 ms
使用我的硬件和配置对ST_Intersects
列进行geo
查询大约需要10秒。
geotest=> SELECT count(*) FROM test_table t WHERE ST_Intersects(t.geo, ST_GeogFromText('SRID=4326;POINT(-104.70348 38.6661)'));
count
-------
1000
(1 row)
Time: 11051.466 ms
结合WHERE
子句,查询仍然在仅几何查询的时间范围内运行。
geotest=> SELECT count(*) FROM test_table t WHERE t.min <= 50 AND t.max >= 50 AND ST_Intersects(t.geo, ST_GeogFromText('SRID=4326;POINT(-104.70348 38.6661)'));
count
-------
1000
(1 row)
Time: 11072.337 ms
如果它有用,这里是规划师如何接近合并查询:
geotest=> EXPLAIN ANALYZE SELECT count(*) FROM test_table t WHERE t.min <= 50 AND t.max >= 50 AND ST_Intersects(t.geo, ST_GeogFromText('SRID=4326;POINT(-104.70348 38.6661)'));
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=8.43..8.44 rows=1 width=8) (actual time=10962.332..10962.333 rows=1 loops=1)
-> Index Scan using test_table_gidx on test_table t (cost=0.15..8.42 rows=1 width=0) (actual time=8.199..10961.612 rows=1000 loops=1)
Index Cond: (geo && '0101000020E6100000F758FAD0052D5AC0CCEEC9C342554340'::geography)
Filter: ((min <= 50) AND (max >= 50) AND (_st_distance(geo, '0101000020E6100000F758FAD0052D5AC0CCEEC9C342554340'::geography, '0'::double precision, false) < '1e-05'::double precision))
Rows Removed by Filter: 1000
Planning time: 0.260 ms
Execution time: 10962.606 ms
有没有办法只对匹配ST_Intersects
子句的min
/ max
过滤器的记录执行WHERE
比较?
答案 0 :(得分:1)
使用CTE作为优化范围。
WITH t1 AS (
SELECT *
FROM test_table t
WHERE t.min <= 50 AND t.max >= 50
)
SELECT *
FROM t1
JOIN test_table AS t2
ON t2.id=t1.id
AND ST_Intersects(
t2.geom,
ST_SetSRID(ST_MakePoint(-104.70348, 38.6661),4326)
);