代码之家  ›  专栏  ›  技术社区  ›  Janning Vygen

我应该激活c3p0语句池吗?

  •  18
  • Janning Vygen  · 技术社区  · 14 年前

    我们正在运行java6/hibernate/c3p0/postgresql堆栈。 我们的JDBC驱动程序是8.4-701.JDBC3

    关于准备好的陈述,我有几个问题。我读过 优秀的文档 Prepared Statements

    但是我仍然有一个问题,如何用PostgreSQL配置c3p0。

    现在我们有

     c3p0.maxStatements = 0
     c3p0.maxStatementsPerConnection  =   0
    

    在我的理解中,准备好的语句和语句池是两种不同的东西:

    我们的Hibernate堆栈使用准备好的语句。PostgreSQL正在缓存 执行计划。下次使用相同的语句时,PostgreSQL会重用 执行计划。这样可以节省数据库中的时间规划语句。

    另外,C3P0可以缓存Java“.SQL.PravaReDealSt声明”的Java实例。 这意味着它正在缓存Java对象。所以当使用时
    c3p0.maxStatementsPerConnection=100它最多缓存100个不同的
    物体。它节省了创建对象的时间,但这与 PostgreSQL数据库及其准备的语句。

    对吗?

    当我们使用大约100种不同的语句时,我会设置 c3p0.maxStatementsPerConnection=100

    但是c3p0文档说 c3p0 known shortcomings

    语句池的开销是 太高了。对于那些没有 执行重要的预处理 准备声明,汇集 开销超过任何节省。 因此语句池被关闭 默认情况下。如果你的司机 预处理准备声明, 尤其是通过IPC RDBMS,你可能会看到 显著的性能提高 打开语句池。(这样做 通过设置配置属性 MAXStatements或 MaxStatementsPerConnection到值 大于零)。

    那么:用c3p0和postgresql激活maxStatementsPerConnection是否合理? 激活它有真正的好处吗?

    亲切问候 詹宁

    2 回复  |  直到 14 年前
        1
  •  25
  •   araqnid    14 年前

    我暂时不记得Hibernate是实际存储PreparedStatement实例本身,还是依赖连接提供程序来重用它们。(对batcherimpl的快速扫描表明,如果连续多次执行同一个SQL,则会重用最后一条PreparedStatement)

    我认为c3p0文档试图指出的一点是,对于许多JDBC驱动程序来说,PreparedStatement并不有用:有些驱动程序最终只会简单地拼接客户端中的参数,然后将构建的SQL语句传递给数据库。对于这些驱动程序来说,PreparedStatements一点好处也没有,任何重用它们的工作都被浪费了。(The Postgresql JDBC FAQ 说这是在Sever协议版本3之前的PostgreSQL的情况,在 documentation )

    对于确实有效地处理PreparedStatement的驱动程序来说,实际上仍然有必要重用PreparedStatement实例以获得任何好处。例如,如果驱动程序实现:

    • connection.PrepareStatement(SQL)-创建服务器端语句
    • preparedStatement.execute(..)etc-执行服务器端语句
    • preparedStatement.close()-释放服务器端语句

    鉴于此,如果应用程序总是打开一个准备好的语句,执行它一次,然后再次关闭它,那么 仍然 没有好处;事实上,情况可能更糟,因为现在可能会有更多的往返旅行。因此,应用程序需要挂起PreparedStatement实例。当然,这会导致另一个问题:如果应用程序挂起的太多,并且每个服务器端语句都消耗一些资源,那么这会导致服务器端问题。在有人直接使用JDBC的情况下,这可能是手工管理的——一些语句是已知的可重用的,因此是准备好的;一些不是,只是使用临时语句实例。(这跳过了准备好的语句的其他好处:处理参数转义)

    所以这就是为什么c3p0和其他连接池也有准备好的语句缓存——它允许应用程序代码避免处理所有这些。这些语句通常保存在一些有限的LRU池中,因此公共语句重用PreparedStatement实例。

    最后一个难题是,JDBC驱动程序自己可能会决定是否聪明并做到这一点;服务器自己也可能会决定是否聪明并检测到提交了一个结构类似于前一个语句的客户机。

    考虑到Hibernate本身不保存PreparedStatement实例的缓存,您需要让c3p0这样做才能获得它们的好处。(由于重用缓存的计划,应该减少公共语句的开销)。如果c3p0不缓存准备好的语句,那么驱动程序只会看到应用程序正在准备一个语句,执行它,然后再次关闭它。看起来JDBC驱动程序有一个 "threshold" setting 在应用程序总是这样做的情况下,避免准备/执行服务器开销。所以,是的,您需要有c3p0 do语句缓存。

    希望能帮上忙,对不起,有点喘不过气来。答案是 .

        2
  •  2
  •   wwadge    14 年前

    记住,语句必须根据 连接 这意味着你将不得不消耗相当大的内存,而且要花很长时间才能看到任何好处。因此,如果您将其设置为使用100个要缓存的语句,那么实际上是100*个连接数,或者100/个连接数,但是您仍然需要花费相当长的时间,直到缓存产生任何有意义的效果。