我已阅读prepareStatement(String sql)
的说明以及与PreparedStatement
的性能和缓存相关的大量帖子,我很清楚数据库将解析并编译预准备语句的查询,以便随后相同的查询,另一轮解析和编译不会发生,但我不清楚是否:
prepareStatement(String sql)
都会导致数据库调用?我想会的。prepareStatement(String sql)
都会导致数据库调用,然后我不明白这行来自docs是什么意思 - “有或没有IN参数的SQL语句可以预先编译并存储在一个PreparedStatement对象。“?因为我们得到的真正的性能优势是在RDBMS方面,PreparedStatement
对象在做什么呢?PreparedStatement
对象执行了一个查询(简单的SELECT,没有参数化),现在如果我使用Statement
对象执行相同的查询,那么RDBMS是否仍会解析和编译或不会? 答案 0 :(得分:2)
以下内容仅适用于Oracle数据库JDBC驱动程序。其他驱动因素可能不同。
对Connection.prepareStatement(String)的调用不会进行数据库往返。它构造一个新的PreparedStatement并将SQL String存储在其中。就是这样。
即使未使用的PreparedStatements也是中等复杂的,所以这不是一个完全无关紧要的电话。即便如此,缓存未使用的PreparedStatements也没什么价值。建造新建筑的成本很低。强调“未使用”。第一次执行PreparedStatement会执行完整的往返并完成构建PreparedStatement。使用PreparedStatement一旦重用它的成本远远低于创建新的并且第一次使用它的成本。
对于客户端和服务器,在两个PreparedStatements中执行相同的SQL比执行两次PreparedStatement要贵。对于客户来说,额外的成本非常简单。这是完全构建第二个PreparedStatement的成本,这包括客户在第一次执行往返之后所做的工作。数据库中的事情并非如此简单。
Oracle数据库具有多级缓存和重用,可最大程度地降低多次执行给定SQL字符串的成本。 PreparedStatement包含游标ID。该id指的是服务器中的游标。游标是复杂的结构,是数据库表示SQL执行的表示。某些结构可以由执行相同SQL的其他游标共享。一些结构对于单次执行是唯一的。某些结构可以在执行SQL而不是其他游标的某些游标之间共享。这是一个复杂的系统。
作为一般规则,创建新的PreparedStatement需要进行硬解析。如果服务器之前已经看过SQL,则硬解析可能不是完整的硬解析,因为服务器可以重用某些游标结构。如果应用程序重新执行PreparedStatement,那么理想情况下服务器不必对游标执行任何操作;它只是重新执行它。但是在很多情况下服务器必须先进行软解析才能重新执行。软解析比硬解析工作少,但不是微不足道。
以上忽略了隐式语句缓存。 Implicit Statement Cache存储通过执行Prepared和Callable语句创建的结构。如果应用程序执行SQL,则关闭PreparedStatement,然后使用相同的SQL创建新的PreparedStatement,重新使用第一次执行创建的结构。首次执行缓存中的PreparedStatement的成本与所有实际目的相同,与重新执行相同的PreparedStatement相同。
答案 1 :(得分:1)
是的,每次调用prepareStatement
都会导致数据库调用。如果不是,那么可能是这种情况:
execute("create table x(y integer)");
prepareStatement("select * from x"); // #1
execute("rename table x to old_x");
execute("create table x(z varchar(100))");
prepareStatement("select * from x"); // #2 - this stamenent is not equal to previous
PreparedStatement
通常是游标句柄的包装器。 prepareStatement
将SQL语句发送到RDBMS。 RDBMS编译它并返回它的句柄。下一次数据库调用使用此句柄,因此RDBMS将使用编译语句。
这取决于RDBMS。比方说,在这种情况下,Oracle将使用“软解析”。软解析意味着比数据库在其缓存中定位相等的语句并尽可能使用它。它比重新编译更有效,但比使用预准备语句更有效。
答案 2 :(得分:0)
虽然@Sanders和@Douglas很好但是它们不完整(即使只考虑JDBC驱动程序),所以我也提出了我的答案,这也是不完整的,我建议阅读所有3个答案以获得良好的知识:
connection. prepareStatement()
然后如果它是一个独立的Java程序,那么如果它是一个J2EE服务器就会发生到服务器的往返由于JEE PreparedStatement缓存