【问题标题】:Why is the PostgreSQL JDBC prepared statement threshold defaulted to 5?为什么 PostgreSQL JDBC 准备语句阈值默认为 5?
【发布时间】:2011-12-27 14:57:22
【问题描述】:

默认情况下,参数语句阈值设置为5,而不是1。即,

((PGStatement) my_statement).getPrepareThreshold()

默认总是返回 5。

那会是什么原因呢?为什么我不想在执行查询的前 4 次使用服务器端准备好的语句?我不明白为什么我会将此设置为 1 以外的其他值,以及为什么默认情况下不设置为 1。

你能解释一下吗?非常感谢。

【问题讨论】:

    标签: postgresql jdbc prepared-statement


    【解决方案1】:

    服务器端准备好的语句消耗服务器端资源来存储语句的执行计划。阈值提供了一种启发式方法,它导致准备实际“经常”使用的语句。 “经常”的定义默认为 5。

    请注意,服务器端准备好的语句可能会导致执行计划不佳,因为它们不是基于准备期间传递的参数。如果传递给预准备语句的参数对特定索引(例如)具有不同的选择性,则预准备语句的一般查询计划可能不是最佳的。再举一个例子,如果你遇到的情况是查询的执行远大于创建解释计划的成本,并且由于缺少绑定参数而没有正确设置解释计划,你最好不要使用服务器端准备好的语句。

    当驱动程序达到阈值时,它会准备如下语句:

        if (!oneShot)
        {
            // Generate a statement name to use.
            statementName = "S_" + (nextUniqueID++);
    
            // And prepare the new statement.
            // NB: Must clone the OID array, as it's a direct reference to
            // the SimpleParameterList's internal array that might be modified
            // under us.
            query.setStatementName(statementName);
            query.setStatementTypes((int[])typeOIDs.clone());
        }
    

    语句名称作为有线协议的一部分发送,它告诉 Postgres 在服务器端准备它。

    【讨论】:

    • 所以本质上如果我们使用预处理语句功能(Connection.prepareStatement(...) 函数)进行一次性查询,我们只是受益于参数绑定的好处,没有SQL注入风险,等等?这是否意味着 JDBC 驱动程序会将准备好的语句转换为常规语句以“伪造”此参数绑定的前 4 次?如果是这样,那就很有意义了。
    • 它不会伪造绑定...唯一的区别是在发送到服务器时是否将名称附加到查询中(请参阅我在答案中的编辑)。
    • 谢谢,我现在明白了。命名查询将导致在服务器上保存执行计划。由于这样做代价高昂,因此默认情况下仅在查询执行 5 次后才执行此操作。
    【解决方案2】:

    5 是随机挑选的,可由用户配置。 除了在服务器上使用资源之外,命名语句还需要驱动程序进行额外的往返来描述语句的参数。这是驱动程序默认不使用命名语句的主要原因。

    【讨论】:

      猜你喜欢
      • 2014-02-05
      • 2011-07-09
      • 1970-01-01
      • 2012-05-31
      • 2018-04-10
      • 1970-01-01
      • 2015-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多