PreparedStatements和性能

所以我一直听说PreparedStatements对性能有好处。

我们有一个Java应用程序,在这个应用程序中我们使用常规的“Statement”比使用“PreparedStatement”更多。 在尝试使用更多的PreparedStatements的同时,我正在尝试更全面地了解PreparedStatements如何工作 – 在客户端和服务器端。

因此,如果我们有一些典型的CRUD操作并在应用程序中重复更新对象,是否有助于使用PS? 我明白,我们将不得不每次closuresPS,否则会导致游标泄漏。

那么它对性能有什么帮助? 是否驱动caching预编译语句,并给我一个副本,下一次我做connection.prepareStatement? 还是DB服务器有帮助?

我理解有关PreparedStatements的安全性好处的争论,我赞赏下面强调它的答案。 不过,我真的希望继续关注PreparedStatements的性能优势。

更新:当我说更新数据时,我真的更多的是随机地多次调用这个方法。 我理解下面提供的答案中的优点,要求在循环中重新使用语句。

// some code blah blah update(); // some more code blah blah update(); .... public void update () throws SQLException{ try{ PreparedStatement ps = connection.prepareStatement("some sql"); ps.setString(1, "foobar1"); ps.setString(2, "foobar2"); ps.execute(); }finally { ps.close(); } } 

没有办法真正重用'ps'java对象,我明白,实际的connection.prepareStatement调用是相当昂贵的。

这是什么使我回到原来的问题。 这是“一些SQL”的PreparedStatement仍然被caching和重用,我不知道的封面?

我还要提到,我们支持几个数据库。

提前致谢。

准备好的陈述可以在重新使用您准备的相同陈述时提高绩效:

 PreparedStatement ps = connection.prepare("SOME SQL"); for (Data data : dataList) { ps.setInt(1, data.getId()); ps.setString(2, data.getValue(); ps.executeUpdate(); } ps.close(); 

这比在循环中创build语句要快得多。

一些平台还caching准备好的语句,以便即使closures它们,也可以更快地重build它们。

但是,即使性能相同,您仍然应该使用预准备语句来防止SQL注入。 在我的公司这是一个面试问题; 弄错了,我们可能不会雇用你。

准备好的陈述主要是关于performance的概念是一种误解,虽然这是相当普遍的。

另一张海报提到,他注意到Oracle和SQL Server的速度提高了大约20%。 我已经注意到与MySQL相似的数字。 事实certificate,parsing查询并不是所涉及工作的重要组成部分。 在一个非常繁忙的数据库系统中,也不清楚查询parsing是否会影响整体吞吐量:总的来说,它可能只是消耗了CPU时间,否则在数据从磁盘回来的时候会是空闲的。

所以作为使用准备好的语句的一个原因, 防止SQL注入攻击远远超过了性能改进。 如果你不担心SQL注入攻击,你可能应该…

准备好的语句确实在第一次使用后被caching,这是他们在标准语句上的performance。 如果你的陈述没有改变,那么build议使用这种方法。 它们通常存储在一个语句caching中以供更改使用。

更多信息可以在这里find:

http://www.theserverside.com/tt/articles/article.tss?l=Prepared-Statments

你可能想看看Spring JDBCTemplate作为直接使用JDBC的替代方法。

http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html

parsingSQL不是唯一的事情。 validation表和列确实存在,创build一个查询计划等等。您用PreparedStatement支付一次。

绑定以防止SQL注入确实是一件非常好的事情。 IMO不够。 在进入持久层之前,您仍然应该validationinput。

有趣的是:我几年前在Java 1.4中使用ODBC做了准备与dynamic语句的实验,同时使用了Oracle和SQL Server后端。 我发现准备好的语句对某些查询的速度可能会快20%,但是关于哪些查询在什么程度上有所改进,存在供应商特定的差异。 (这应该不会令人惊讶,真的。)

底线是,如果您将重复使用相同的查询,预准备的语句可能有助于提高性能; 但是如果你的performance够糟糕,你需要立即采取措施,不要指望使用准备好的语句来激励你。 (20%通常没什么可写的。)

当然,你的里程可能会有所不同。

这是什么使我回到原来的问题。 这是“一些SQL”的PreparedStatement仍然被caching和重用,我不知道的封面?

至less在Oracle中是这样。 按照Oracle®Database JDBC开发人员指南隐式语句caching (已添加重点),

当启用隐式语句caching时,当您调用此语句对象的close方法时,JDBC会自动caching准备好的或可调用的语句。 使用标准连接对象和语句对象方法来高速caching和检索准备好的和可调用的语句。

纯语句不会隐式高速caching,因为隐式语句高速caching使用SQLstring作为关键字,并且在没有SQLstring的情况下创build普通语句。 因此,隐式语句caching仅适用于使用SQLstring创build的OraclePreparedStatementOraclePreparedStatement对象。 您不能在OracleStatement中使用隐式Statementcaching。 在创buildOraclePreparedStatementOraclePreparedStatement ,JDBC驱动程序将自动searchcaching中的匹配语句

那么它对性能有什么帮助? 是否驱动caching预编译语句,并给我一个副本,下一次我做connection.prepareStatement? 还是DB服务器有帮助?

我会根据performance来回答。 这里的其他人已经规定PreparedStatement对SQL注入是有弹性的(有利的)。

应用程序(JDBC Driver)创buildPreparedStatement并使用占位符( ? )将其传递给RDBMS。 RDBMS预编译,应用收到的PreparedStatement查询优化(如果需要的话),并且(在一些情况下)通常将其caching。 在执行PreparedStatement ,使用了预编译的PreparedStatement ,用每个占位符的相关值replace每个占位符并进行计算。 这与编译它并直接执行它的Statement相反, PreparedStatement编译和优化查询一次 。 现在,上面解释的这个场景并不是所有JDBC供应商的绝对情况,但本质上这就是PreparedStatement如何被使用和操作。

就正常陈述而言,准备好的陈述在性能方面具有一些优势,这取决于你如何使用它们。 如前所述,如果您需要使用不同的参数多次执行相同的查询,则可以重新使用准备好的语句,并只传递新的参数集。 性能改进取决于您正在使用的特定驱动程序和数据库。

例如,在数据库性能方面,Oracle数据库在每次计算之后caching一些查询的执行计划(对于所有版本和Oracle的所有configuration,这不是真实的)。 即使closures语句并打开新语句,也可以find改进,因为这是在RDBMS级别完成的。 只有当后面的两个查询(char-by-char)相同时,才会激活这种caching。 这不适用于正常的语句,因为参数是查询的一部分,并产生不同的SQLstring。

其他一些RDBMS可能更“智能”,但我不希望他们会使用复杂的模式匹配algorithm来caching执行计划,因为这会降低性能。 您可能会争辩说,执行计划的计算只是查询执行的一小部分。 对于一般情况,我同意,但是这取决于。 请记住,通常情况下,计算执行计划可能是一项昂贵的任务,因为rdbms需要咨询像统计数据(不仅是Oracle)的非内存数据。

然而,关于caching的争论从执行计划到提取过程的其他部分。 对RDBMS多次执行相同的查询(无需深入查看特定实现)有助于在JDBC(驱动程序)或RDBMS级别识别已计算的结构。 如果您现在在性能上没有发现任何特别的优势,那么您不能排除性能改进将在将来/替代版本的驱动程序/ rdbms中实现。

通过在批处理模式下使用预处理语句可以获得更新的性能改进,但这是另一回事。

1. PreparedStatement允许你写dynamic参数查询

通过在Java中使用PreparedStatement,可以编写参数化的sql查询,并通过使用相同的sql查询发送不同的参数,这比创build不同的查询要好得多。

2. PreparedStatement比Java中的Statement快

使用PreparedStatement的主要好处之一是性能更好。 PreparedStatement获得预编译在数据库中,并且访问计划也被caching在数据库中,这允许数据库执行使用预准备语句编写的参数化查询比正常查询快得多,因为它具有较less的工作量。 您应该总是尝试在生产JDBC代码中使用PreparedStatement来减less数据库负载。 为了获得性能上的好处,值得注意的是只使用参数化的sql查询版本,而不是string连接

3. PreparedStatement可以防止Java中的SQL注入攻击

阅读更多信息: http : //javarevisited.blogspot.com/2012/03/why-use-preparedstatement-in-java-jdbc.html#ixzz3LejuMnVL

简短的回答:

PreparedStatement有助于提高性能,因为通常DB客户端会重复执行相同的查询,这样可以对初始查询进行 一些预处理以加快以下重复查询的速度

很长的回答:

根据维基百科 ,使用准备语句的典型工作stream程如下:

准备 :语句模板由应用程序创build并发送到数据库pipe理系统(DBMS)。 某些值未指定,称为参数,占位符或绑定variables(在下面标记为“?”):INSERT INTO PRODUCT(name,price)VALUES(?,?)

(预编译) :DBMSparsing,编译并在语句模板上执行查询优化,并存储结果而不执行。

执行 :稍后,应用程序提供(或绑定)参数值,DBMS执行该语句(可能返回结果)。 应用程序可以根据需要以不同的值执行多次该语句。 在这个例子中,它可能为第一个参数提供“Bread”,为第二个参数提供“1.00”。

准备:

在JDBC中,“准备”步骤通过调用java.sql.Connection完成。 prepareStatement (String sql)API。 根据其Javadoc:

此方法针对处理从预编译中受益的参数化SQL语句进行了优化。 如果驱动程序支持预编译,prepareStatement方法会将语句发送到数据库进行预编译。 某些驱动程序可能不支持预编译。 在这种情况下,该语句可能不会被发送到数据库,直到PreparedStatement对象被执行。 这对用户没有直接影响; 但是,它影响哪些方法会抛出某些SQLException对象。

由于调用此API可能会将SQL语句发送到数据库,因此这通常是一个昂贵的调用。 根据JDBC驱动程序的实现,如果具有相同的sql语句模板,为了获得更好的性能,可能必须避免在客户端多次调用同一个sql语句模板。

预编译:

发送的语句模板将在数据库上预编译并在数据库服务器中caching。 数据库可能会使用连接和sql语句模板作为键,预编译查询和计算的查询计划作为caching中的值。 parsing查询可能需要validation表,要查询的列,所以它可能是一个昂贵的操作,计算查询计划也是一个昂贵的操作。

执行:

对于以下来自同一连接和sql语句模板的查询,预编译的查询和查询计划将直接从数据库服务器的caching中查找,而无需重新计算。

结论:

从绩效的angular度来看,使用准备陈述是一个两阶段的过程:

  1. 第一阶段,准备和预编译,这个阶段预计将完成一次,并增加一些性能开销。
  2. 阶段2,重复执行相同的查询,因为阶段1对查询进行了一些预处理,如果重复查询的次数足够大,这可以为同一查询节省大量的预处理工作。

如果你想知道更多的细节,有一些文章解释了PrepareStatement的好处:

  1. http://javarevisited.blogspot.com/2012/03/why-use-preparedstatement-in-java-jdbc.html
  2. http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html