一 前言
建立空间索引的图形列通过表达式、函数、类型转换后导致索引失效。
部分空间函数根本不会走空间索引。
索引效率低,IO与CPU放大严重。
二 索引失效案例
2.1 表达式导致索引失效
select * from test where (value+2)<10;
select * from test where value<(10-2);
create table poi(gid serial primary key,name text,geom geometry(Point,4326));create index poi_geom_idx on poi using gist(geom);--区域内构造测试数据insert into poi(geom)select (st_dump(ST_GeneratePoints(ST_MakeEnvelope(113,24,125,35,4326),2500000))).geom;

explain select a.* from poi a where ST_Intersects(ST_Buffer(a.geom,0.01),ST_SetSrid(ST_MakePoint(118.3749,32.0987),4326)); QUERY PLAN----------------------------------------------------------------------------------------------------------------------------------------------------Gather (cost=1000.00..52115609.00 rows=250 width=68)Workers Planned: 2-> Parallel Seq Scan on poi a (cost=0.00..52114584.00 rows=104 width=68)Filter: st_intersects(st_buffer(geom, '0.01'::double precision, ''::text), '0101000020E61000004ED1915CFE975D40BF0E9C33A20C4040'::geometry)JIT:Functions: 2Options: Inlining true, Optimization true, Expressions true, Deforming true(7 rows)Time: 145.681 ms
explain select a.* from poi a where ST_Intersects(a.geom,st_buffer(ST_SetSrid(ST_MakePoint(118.3749,32.0987),4326),0.01)); QUERY PLAN-----------------------------------------------------------------------------Index Scan using poi_geom_idx on poi a (cost=0.41..149.50 rows=5 width=68)
方案三:使用ST_Distance实现,就是判定poi点与我的位置之间距离小于1公里即可,很明显是遍历poi点与我的位置的距离做判断。
explain select a.* from poi a where ST_Distance(a.geom,ST_SetSrid(ST_MakePoint(118.3749,32.0987),4326))<0.01;QUERY PLAN--------------------------------------------------------------------------------------------------------------------------------Gather (cost=1000.00..26159854.80 rows=833333 width=68)Workers Planned: 2-> Parallel Seq Scan on poi a (cost=0.00..26075521.50 rows=347222 width=68)Filter: (st_distance(geom, '0101000020E61000004ED1915CFE975D40BF0E9C33A20C4040'::geometry) < '0.01'::double precision)JIT:Functions: 2Options: Inlining true, Optimization true, Expressions true, Deforming true(7 rows)Time: 1.015 ms
explain select a.* from poi a where ST_DWithin(a.geom,ST_SetSrid(ST_MakePoint(118.3749,32.0987),4326),0.01);QUERY PLAN-----------------------------------------------------------------------------------------------------------------------------Index Scan using poi_geom_idx on poi a (cost=0.54..149.62 rows=250 width=68)Index Cond: (geom && st_expand('0101000020E61000004ED1915CFE975D40BF0E9C33A20C4040'::geometry, '0.01'::double precision))Filter: st_dwithin(geom, '0101000020E61000004ED1915CFE975D40BF0E9C33A20C4040'::geometry, '0.01'::double precision)(3 rows)
explain select a.* from poi a where ST_DWithin(a.geom::geography,ST_SetSrid(ST_MakePoint(118.3749,32.0987),4326)::geography,1000);QUERY PLAN------------------------------------------------------------------------------------------------------------------------------------------------Gather (cost=1000.00..26076546.50 rows=250 width=68)Workers Planned: 2-> Parallel Seq Scan on poi a (cost=0.00..26075521.50 rows=104 width=68)Filter: st_dwithin((geom)::geography, '0101000020E61000004ED1915CFE975D40BF0E9C33A20C4040'::geography, '1000'::double precision, true)JIT:Functions: 2Options: Inlining true, Optimization true, Expressions true, Deforming true(7 rows)
--对必须要进行类型转换计算,可以预先建立表达式索引create index poi_geogra_idx on poi using gist((geom::geography));--查询计划explain select a.* from poi a where ST_DWithin(a.geom::geography,ST_SetSrid(ST_MakePoint(118.3749,32.0987),4326)::geography,1000);QUERY PLAN--------------------------------------------------------------------------------------------------------------------------------------------------Bitmap Heap Scan on poi a (cost=14.47..7181.94 rows=250 width=68)Filter: st_dwithin((geom)::geography, '0101000020E61000004ED1915CFE975D40BF0E9C33A20C4040'::geography, '1000'::double precision, true)-> Bitmap Index Scan on poi_geogra_idx (cost=0.00..14.41 rows=250 width=0)Index Cond: ((geom)::geography && _st_expand('0101000020E61000004ED1915CFE975D40BF0E9C33A20C4040'::geography, '1000'::double precision))(4 rows)Time: 0.813 ms
同一个空间查询业务,可以同时有很多种Spatial SQL可以达到同样的查询结果,一定要仔细分析判定哪些方案根本就不能用,能用的方案对比下哪个性能更好。
原则上不要对建立空间索引的图形列在业务应用时对其进行表达式计算或强制类型转换,这会导致索引失效。
特殊情况下,可以通过建立表达式索引兼顾业务功能和查询性能。
文章转载自Spatial Data,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




