如何解决PostgreSQL函数的运行速度比直接查询慢
当我尝试将一个简单的sql语句包装为一个函数时,我的问题就开始了。该请求花了几毫秒完成,开始花费数秒。 我在google上可以阅读所有内容,但这全都与使用函数参数有关。 然后我摆脱了参数,但这并不能解决问题。
select fn_tz(idata.system_timestamp),gp.zname,fc.*
from jv idata
join gp on st_distance(waypoint,geom)=0
join fc ON
idata.fare_code = fc.fare_code AND
fc.validity @> fn_tz(idata.system_timestamp)::date and
fc.polygon_name = gp.name
where idata.item_id='21159704983720122917';
当我直接运行此查询时,大约需要80毫秒才能执行。但是,如果我将未经修改的相同查询放在函数主体中,则大约需要10秒钟!
无论如何,我已经尝试了所有想到的事情
- 常规PLPGsql函数(
return query ...
) - 常规sql函数(
select ...
) - 具有动态SQL查询(
return query execute 'select ...'
)的PLPGsql函数 - 终于我尝试了准备/执行语句
以上所有方法给出的结果相同-10秒。
然后我在准备好的语句上运行EXPLAIN ANALYZE EXECUTE ...
,但是即使从它的输出中,我也无法理解为什么它运行10秒
Hash Join (cost=75.05..962862.24 rows=110 width=8) (actual time=1.075..10290.527 rows=476091 loops=1)
Hash Cond: ((idata.fare_code = fc.fare_code) AND (gp.name = (fc.polygon_name)::text))
Join Filter: (fc.validity @> (fn_tz(idata.system_timestamp))::date)
-> nested Loop (cost=0.00..925098.69 rows=59399 width=54) (actual time=0.298..8300.070 rows=53922 loops=1)
Join Filter: (st_distance(idata.waypoint,gp.geom) = '0'::double precision)
Rows Removed by Join Filter: 2212398
-> Seq Scan on jv idata (cost=0.00..4402.99 rows=53999 width=54) (actual time=0.039..33.038 rows=53960 loops=1)
Filter: (item_id = '21159704983720122917'::text)
Rows Removed by Filter: 3079
-> Materialize (cost=0.00..13.30 rows=220 width=64) (actual time=0.000..0.003 rows=42 loops=53960)
-> Seq Scan on gp (cost=0.00..12.20 rows=220 width=64) (actual time=0.006..0.025 rows=42 loops=1)
-> Hash (cost=40.22..40.22 rows=2322 width=16) (actual time=0.717..0.717 rows=2268 loops=1)
Buckets: 4096 Batches: 1 Memory Usage: 141kB
-> Seq Scan on fc (cost=0.00..40.22 rows=2322 width=16) (actual time=0.008..0.332 rows=2322 loops=1)
Planning Time: 0.008 ms
Execution Time: 10324.558 ms
令人惊讶的是,如果我在原始查询上运行EXPLAIN ANALYZE
,它也将花费大约10秒钟的时间,并产生几乎相同的执行计划。
我的服务器-Google Cloud Platform上Postgres 11.8的托管实例
我还能做什么/尝试?
更新: 似乎我需要强调-我没有在寻找改善查询性能的方法。直接查询运行80毫秒,对此我感到满意。 我想找到原因-为什么直接查询比函数主体快 100次(!)。
解决方法
fn_tz
可能会降低性能2秒钟左右,但是主要问题是您使用的是st_distance
而不是st_dwithin
,可以通过索引来支持它:
select fn_tz(idata.system_timestamp),gp.zname,fc.*
from jv idata
join gp on st_dwithin(waypoint,geom,0)
join fc ON
idata.fare_code = fc.fare_code AND
fc.validity @> fn_tz(idata.system_timestamp)::date and
fc.polygon_name = gp.name
where idata.item_id='21159704983720122917';
索引将是:
CREATE INDEX ON jv USING gist (waypoint);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。