postgresql - PostgreSQL 函数运行速度比直接查询慢得多
问题描述
当我试图将一个简单的 sql 语句包装为一个函数时,我的问题就开始了。需要几毫秒才能完成的请求开始需要几秒钟。我在谷歌上阅读了所有我能读到的东西,但都是关于使用函数参数的。然后我摆脱了参数,但这并没有解决问题。
所以,现在我有以下 SQL 语句
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 查询的 PLPGSQL 函数 (
return query execute 'select ...'
) - 终于我尝试了准备/执行语句
所有上述方法都给出相同的结果 - 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 的托管实例
我还能做什么/尝试?
Upd: 看来我需要强调一下——我不是在寻找提高查询性能的方法。直接查询运行 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);
推荐阅读
- javascript - javascript将json数据迭代到geojson中以获取传单
- r - 如何在 R 中使用 tidyr group_by 函数添加其他列?
- python - Python中优化的矩阵乘法库(类似于Matlab)但不是numpy
- css - 使用 grid-row-end 时网格子交换位置
- node.js - Laradock - 添加自定义 npm 包
- python - Tk画布可以导入postscript文件并显示吗?
- java - Intellj 没有创建 gradle 包装器属性
- css - 使用 CSS、Wordpress、Avada Them、Fusion Builder 隐藏特色图片
- android - 使用 progressTint 的 RatingBar 的色调不准确
- node.js - 为什么 scr 路径没有 . / 如果它们在同一个目录中?