Postgresql 为什么当我将查询放入函数时,它的执行速度要慢76倍?

Postgresql 为什么当我将查询放入函数时,它的执行速度要慢76倍?,postgresql,query-planner,postgresql-12,Postgresql,Query Planner,Postgresql 12,当我将下一个查询放入函数时,它会慢76倍。 计划中唯一的区别是:位图索引扫描与索引扫描 计划1: 计划2: 解释分析、成本、详细信息、缓冲区、JSON格式 选择 按t.o.id划分的t.group_suma之和为total_suma, * 从…起 选择 将ocd项目成本合计为集团成本, 将ocd项目汇总为组, 最大ocd.ic.消耗量为消耗量, 强迫症发作期, 强迫症 来自订单成本详情TSTZ范围“2019-04-01”、“2019-05-01”ocd 按ocd.o、ocd.ic.消费周期分

当我将下一个查询放入函数时,它会慢76倍。 计划中唯一的区别是:位图索引扫描与索引扫描

计划1:

计划2:

解释分析、成本、详细信息、缓冲区、JSON格式 选择 按t.o.id划分的t.group_suma之和为total_suma, * 从…起 选择 将ocd项目成本合计为集团成本, 将ocd项目汇总为组, 最大ocd.ic.消耗量为消耗量, 强迫症发作期, 强迫症 来自订单成本详情TSTZ范围“2019-04-01”、“2019-05-01”ocd 按ocd.o、ocd.ic.消费周期分组 T 其中,6154和2019-04-01期间的t.o.id:timestamptz ; 解释分析、成本、详细信息、缓冲区、JSON格式 从“2019-04-01”、“2019-05-01”ots订单中选择* 其中,6154中的ots.o.id和ots.o.id@>“2019-04-01”:时间戳 ; 职能:

在目标范围tstzrange默认应用程序期间创建函数顺序\u总计\u suma 返回表 总精度为双精度, 组成本为双精度, 双精度组, 消耗双精度, 消费周期tstzrange, o订单 语言sql 稳定的 作为$$ 选择 按t.o.id划分的t.group_suma之和为total_suma, * 从…起 选择 将ocd项目成本合计为集团成本, 将ocd项目汇总为组, 最大ocd.ic.消耗量为消耗量, 强迫症发作期, 强迫症 来自订单\成本\详细信息\目标\范围ocd 按ocd.o、ocd.ic.消费周期分组 T $$ ; 为什么对于函数内部的查询,在最后一次子查询扫描时进行过滤

有没有可能做点什么使他们平等地工作

UPD 服务器版本为PostgreSQL 12beta2
由于30000个字符的限制,我发布了一些计划,这些计划完全不同

问题是public.order_bt和split_period子查询之间的连接的结果计数错误。这将导致函数public.service_level_price被评估2882次,而不是一次,这是花费时间的地方

不知道该怎么办我们没有视图定义,这可能很糟糕。提高函数的成本可能没有帮助,因为优化器认为它只会调用一次

事实上,最好的选择可能是

ALTER FUNCTION public.calc_item_suma ROWS 1;
这可能会让优化器选择不同的计划。

感谢IRC的RhodiumLoad:

我怀疑是什么东西阻止了计划者推断t.o.id是安全的,可以通过强迫症组织推过一个小组

这可以通过使其成为一个单独的列来解决

因此,我额外按odc.id列分组。所以我的最后一个问题是:

从中选择* 选择 按t.order\u id划分的t.group\u suma之和为total\u suma, -通过t.o.id将分区上的t.group_suma之和作为total_suma,-对于任何需要2700ms的情况 * 从…起 选择 将ocd项目成本合计为集团成本, 将ocd项目汇总为组, 最大ocd.ic.消耗量为消耗量, 强迫症发作期, 强迫症组织, 作为订单号的ocd.o.id 来自订单成本详情TSTZ范围“2019-04-01”、“2019-05-01”ocd 按ocd.o、ocd.o.id、ocd.ic.U期间分组 T T 其中,t.order_id=6154和t.consumered_period@>'2019-04-01'::timestamptz-这需要2ms -其中t.o.id=6154,t.o.id=6154,t.U期间@>“2019-04-01”::时间戳-这需要2700毫秒 此更改还使通过函数调用更快。我只需要通过order_id字段进行排序:

从“2019-04-01”、“2019-05-01”ots订单中选择* -这需要2.5毫秒 其中,6154中的ots.order_id和ots.consumered_period@>'2019-04-01'::timestamptz -这需要2500毫秒 -其中,6154中的ots.o.id和ots.o.id@>“2019-04-01”:时间戳
您能添加使用explain Analyzie、buffers、format text生成的执行计划吗?这些图隐藏了太多的细节,JSON不需要用户阅读和理解humans@a_horse_with_no_name:@一匹没有名字的马:是的。我是如何做到这一点的?是让带函数的查询更快,还是让第一个不带函数的查询更快?从内容上看,它似乎没有回答您的问题,只是改进了初始查询。@ukaszKamiński:是的。此更改使通过函数调用更快。更新了答案