优化Postgres存储过程

问题描述 投票:2回答:1

我有一个存储过程,执行时间为3分半钟。我有正确的索引,我无法进一步优化它。

有人可以建议我可能会遗漏任何明显的事情吗?

触发:

CREATE CONSTRAINT TRIGGER create_notifications
   AFTER INSERT ON events
   DEFERRABLE INITIALLY DEFERRED FOR EACH ROW
   EXECUTE PROCEDURE create_notifications();

功能定义:

CREATE OR REPLACE FUNCTION public.create_notifications()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$ 
DECLARE 
BEGIN 
INSERT INTO 
notifications(device_id, event_id, status, region, watch_zones_count, watch_zones) 
SELECT 
w.device_id as device_id, 
p.event_id as event_id, 
'pending' as status, 
r.region,
count(w.id) as watch_zones_count, 
json_agg(w.*) as watch_zones 
from
event_polygons p, 
watch_zones w, 
regions r 
where 
p.event_id = NEW.id 
and (CASE 
WHEN p.type='polygon' then St_dwithin(p.polygon, w.position, w.radius*1000) 
WHEN (p.type='circle' and p.radius=0) then St_dwithin(p.position, w.position, w.radius*1000) 
WHEN (p.type='circle' and p.radius>0) then St_dwithin(ST_BUFFER(p.position, p.radius*1000), w.position, w.radius*1000) 
END) 
group by 
w.device_id, 
p.event_id, 
r.id;
RETURN NULL; 
END $function$

这是存储过程的选择部分的解释分析的输出。我用102替换了NEW.id来分析选择

"GroupAggregate  (cost=79678655.89..82662890.29 rows=33978240 width=116) (actual time=207466.320..209109.332 rows=33457 loops=1)"
"  Group Key: w.device_id, p.event_id, r.id"
"  ->  Sort  (cost=79678655.89..80105240.29 rows=170633760 width=155) (actual time=207466.231..207557.324 rows=316723 loops=1)"
"        Sort Key: w.device_id, r.id"
"        Sort Method: external merge  Disk: 46712kB"
"        ->  Nested Loop  (cost=0.00..2691292.15 rows=170633760 width=155) (actual time=11.270..207062.979 rows=316723 loops=1)"
"              ->  Nested Loop  (cost=0.00..558347.40 rows=167288 width=119) (actual time=11.264..206846.622 rows=316723 loops=1)"
"                    Join Filter: CASE WHEN (p.type = 'polygon'::shape_type) THEN ((p.polygon && _st_expand(w."position", ((w.radius * '1000'::numeric))::double precision)) AND (w."position" && _st_expand(p.polygon, ((w.radius * '1000'::numeric))::double precision)) AND _st_dwithin(p.polygon, w."position", ((w.radius * '1000'::numeric))::double precision, true)) WHEN ((p.type = 'circle'::shape_type) AND (p.radius = '0'::numeric)) THEN ((p."position" && _st_expand(w."position", ((w.radius * '1000'::numeric))::double precision)) AND (w."position" && _st_expand(p."position", ((w.radius * '1000'::numeric))::double precision)) AND _st_dwithin(p."position", w."position", ((w.radius * '1000'::numeric))::double precision, true)) WHEN ((p.type = 'circle'::shape_type) AND (p.radius > '0'::numeric)) THEN ((geography(st_transform(st_buffer(st_transform(geometry(p."position"), _st_bestsrid(p."position", p."position")), ((p.radius * '1000'::numeric))::double precision), 4326)) && _st_expand(w."position", ((w.radius * '1000'::numeric))::double precision)) AND (w."position" && _st_expand(geography(st_transform(st_buffer(st_transform(geometry(p."position"), _st_bestsrid(p."position", p."position")), ((p.radius * '1000'::numeric))::double precision), 4326)), ((w.radius * '1000'::numeric))::double precision)) AND _st_dwithin(geography(st_transform(st_buffer(st_transform(geometry(p."position"), _st_bestsrid(p."position", p."position")), ((p.radius * '1000'::numeric))::double precision), 4326)), w."position", ((w.radius * '1000'::numeric))::double precision, true)) ELSE NULL::boolean END"
"                    Rows Removed by Join Filter: 17852"
"                    ->  Seq Scan on event_polygons p  (cost=0.00..8.21 rows=1 width=84) (actual time=0.017..0.025 rows=1 loops=1)"
"                          Filter: (event_id = 102)"
"                          Rows Removed by Filter: 96"
"                    ->  Seq Scan on watch_zones w  (cost=0.00..8799.75 rows=334575 width=152) (actual time=0.092..183.672 rows=334575 loops=1)"
"              ->  Materialize  (cost=0.00..25.30 rows=1020 width=36) (actual time=0.000..0.000 rows=1 loops=316723)"
"                    ->  Seq Scan on regions r  (cost=0.00..20.20 rows=1020 width=36) (actual time=0.004..0.005 rows=1 loops=1)"
"Planning time: 0.406 ms"
"Execution time: 209119.715 ms"
postgresql stored-procedures postgis
1个回答
0
投票

这是一个糟糕的连接条件,使PostgreSQL在watch_zones(position)上使用GiST索引。

使用过滤器和简单连接条件编写三个查询,例如:

... WHERE p.type='polygon'
      AND St_dwithin(p.polygon, w.position, w.radius*1000)

并在结果上创建一个UNION ALL

这些查询中的每一个都应该能够使用索引,并且您将更快。

© www.soinside.com 2019 - 2024. All rights reserved.