智能逻辑查询PostgreSQL函数内部的性能

时间:2017-05-05 10:28:07

标签: java sql performance postgresql jdbc

考虑以下sql查询:

SELECT a,b,c
FROM t
WHERE (id1 = :p_id1 OR :p_id1 IS NULL) AND (id2 = :p_id2 OR :p_id2 IS NULL)

Markus Winand在他的书" SQL Performance explained"将此方法命名为所有中性能最差的反模式之一,并解释了原因(数据库必须为所有过滤器禁用时的最坏情况做好准备)。

但后来他还写道,对于PostgreSQL,只有在重用语句(PreparedStatement)句柄时才会出现问题。

现在假设上面的查询被包装到函数中,例如:

CREATE FUNCTION func(IN p_id1 BIGINT,IN p_id2 BIGINT)
...
 $BODY$
  BEGIN
     ...
  END;
 $BODY$

到目前为止,我误解了几点:

  1. 在功能包装的情况下是否仍会出现此问题? (我已经尝试查看函数调用的执行计划,但Postgres没有向我显示内部函数调用的详细信息,即使使用SET auto_explain.log_nested_statements = ON)。

  2. 让我们说我正在使用遗留项目,并且无法更改函数本身,只能更改java执行代码。在这里避免使用预处理语并每次使用动态查询会更好吗? (假设执行时间很长,最多几秒钟)。说这个,可能是丑陋方法:

  3. getSession().doWork(connection -> {
        ResultSet rs = connection.createStatement().executeQuery("select * from func("+id1+","+id2+")");
        ...
    })
    

1 个答案:

答案 0 :(得分:2)

1。 这取决于。

当不使用预准备语句时,PostgreSQL每次使用参数值计划一次查询。它被称为自定义计划

使用预先准备好的陈述(你是对的,PL / pgSQL函数确实使用预备语句),它更复杂。 PostgreSQL准备语句(解析其文本并存储解析树),但每次执行时都重新计划。自定义计划至少生成5次。之后,如果计划程序的成本低于目前生成的自定义计划的平均成本,则计划程序会考虑使用通用计划(即参数值独立)。

注意,计划的成本是对计划者的估计,而不是实际的I / O操作或CPU周期。

所以,问题可以发生,但你需要运气不好。

2。 您建议的方法不起作用,因为它不会改变函数的行为。

一般来说,PostgreSQL不要使用参数(例如Oracle)就不那么难看了,因为PostgreSQL没有为计划提供共享缓存。准备好的计划存储在每个后端的内存中,因此重新规划不会影响其他会话。

但据我所知,目前没有办法强迫规划人员使用自定义计划(除了5次执行后重新连接......)。