PreparedStatement reuse
Is it possible to use a PreparedStatement after its resultset has been processed? It seems to me like once you iterate through the ResultSet the PreparedStatement can not be executed again with a different set of parameters. Is this correct? I'm using the JdbcOdbcDriver, but I am also looking at the Sybase Jconnect driver. Could this be a driver issue?
here is some pseudocode:
statement = connection.prepareStatement("Select ....");
for (i = 0; i < 10; ++i) {
statement.setInt(1, intVal);
statement.setString(2, strVal);
statement.execute();
result = statement.getResultSet();
process the results
Problem is that with the 2nd iteration I get a java.sql.SQLException: Invalid handle.
Yes, you can. In my programs I generally call prepareStatement() in the class initialization, then reuse the PreparedStatement whenever I need it. I've never had an invalid handle error. My code usually says
result = statement.executeQuery()
instead of what you have there, but I wouldn't expect that to make any difference.
Similar Messages
-
Response time low to display 2700 records
In my program , i have tried to display 2700 records from Database using JSP.
But the response time is very slow. How do i overcome this problem.
My architecture is
JSP - EJB - HelperClass - DB.Find out where the performance bottleneck is
1) Database -> use PreparedStatements,
reuse an open database connection
2) JSP -> Check your string handling, use StringBuffer() for appending
lots of strings together
3) Network response -> Maybe try defining a static IP address for your
server
regards,
Owen -
Reuse of preparedstatements and the connection pool
It seems useful (for performance reasons) to reuse a prepared statement in
subsequent calls to the database. In WebLogic, however, after each call we
return the Connection object to the WebLogic connection pool. A prepared
statement is created on a specific Connection object. The next time we want
to use the same query we get a Connection from the pool, which might be
another instance of the Connection class. Therefor it seems impossible or at
least dangerous to reuse the same prepared statement. Even in the case this
would work we're indirectly using the other Connection, which we already
returned to the pool and which could be retrieved from the pool by someone
else. So, can't we reuse preparedstatements ?Hi Raja,
Currently the only bullet-proof way to make sure that all statements are
cached is to set the cache size to a number of possible prepared statements
in the application.
The only consequence of increased cache size is growing amount of
memory required by a server instance.
Regards,
Slava Imeshev
"Rajiv Jauhari" <[email protected]> wrote in message
news:[email protected]...
Is there an easy way to tell whether the prepared statement cache size one
has set is
appropriate? Some way to monitor cache hit rate or usage count (i.e., the
actual number of statements cached) while running a load test? I'm using
Weblogic 6.1sp3 and Oracle 8.1.7.4.
Another way to think of this question is: is there a negative impact ifthe
cache size is set too large?
In the case of Oracle I believe one might run out of cursors, but is there
any other negative consequence that you know of?
Thanks,
Rajiv
"Joseph Weinstein" <[email protected]> wrote in message
news:[email protected]...
Vyas wrote:
If multiples (of the same statement) can be cached would it not result
in too many
prepared statements of the same type in the cache ?
This could happen
1. When a load test is done when all the threads start doing exactly
the
same work.
Because of contention everybody gets their own statement copy(theoritically, even
if in practice it may not exactly happen like that). In such a case
you
are going
to create load on the database in terms of open cursors.Each thread will get it's own connection, and the statement cache isper-connection.
Cursors, in Oracle's case, do need to be configured to support acache-full of
retained statements. Alternately, the cache should be set to a smallenough size to
require only as many cursors as the DBMS will allow per connection.
Another issue is what happens when the cache limit is hit ?
In the above example let's say cache limit is 50 and I am doing 50
user
load test.
because of load test let's say the cache gets filled with 50 of the
same
statement.
When load test moves to the next sequence of action requiring a
diffrent
statement
what happens to the cache ?
thanks
VyasThe only way a given connection's statement cache will get a duplicatestatement
is if some single JDBC thread required multiple copies of the samestatement. A
multi-user test will usually just ensure that each pooled connectioncaches the
same selection of different statements that the test user used. If thetest user
just repeatedly makes and uses one statement, the first time they do it,the
statement will be cached, and every subsequent repeat of the user codewill get
the same cached statement. The cache will still have 49 empty slotswaiting for
different statements. Currently the cache is simple-minded. It is a
fixed
(configurable)
size per connection, and the first N prepared/callable statements getcached for the
life of the pooled connection that created them. All other subsequentstatements will
be made and closed on a per-connection-use basis. Therefore, it can bethat a startup
or stress load that runs before standard runtime service, and which usessignificantly
different a statement profile could populate the cache with rarely-usedwasted statements.
If I were a customer in this circumstance, I would either prime thecaches, by determining
which statements I wanted cached, and then running a startup class thatreserved all the
pool connections, and made these statements on each before closing them.Alternately,
after startup/stress I would reset the pool, and allow the runtime load
to
fill the cache of
the regenerated pool.
Joe Weinstein at B.E.A.
thanks
Vyas
Joseph Weinstein <[email protected]> wrote:
JS wrote:
It seems useful (for performance reasons) to reuse a prepared
statement
in
subsequent calls to the database. In WebLogic, however, after each
call
we
return the Connection object to the WebLogic connection pool. A
prepared
statement is created on a specific Connection object. The next timewe
want
to use the same query we get a Connection from the pool, which
might
be
another instance of the Connection class. Therefor it seemsimpossible
or at
least dangerous to reuse the same prepared statement. Even in the
case
this
would work we're indirectly using the other Connection, which we
already
returned to the pool and which could be retrieved from the pool bysomeone
else. So, can't we reuse preparedstatements ?We already have you covered! Weblogic caches PreparedStatements along
with the pooled connection they came from. Every time you obtain a
pool
connection and run a prepareStatement() or prepareCall(), we willtransparently
give you a previously made statement, if the SQL exactly matches, andno
other place in the current thread stack is using that statement(multiples
can
be cached)
You are correct, of course, that statements you have should only
be
useable
to you while you have the connection from which they came. We have
you
covered
there too. If you were to try to use any prepared statement that
you'd
gotten
from
a pool connection after you'd put the connection back into the pool,those
statements
would throw an exception saying that they had been made inoperable atthe
time
you'd closed the connection.
Joe Weinstein at B.E.A. -
Could someone comment on my code please. I'm reusing the PreparedStatement (delete) below for different queries before closing the PreparedStatement (delete is closed in this.close()). The API for Statement.close() states:
Releases this Statement object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed. It is generally good practice to release resources as soon as you are finished with them to avoid tying up database resources.
...but what resources would be wasted if the PreparedStatement is reused AND is this opening the app up to innefficency/overhead?
Your reply is appreciated. Code below....
public boolean cascadeDeleteRfxForm() throws SQLException, Exception{
boolean deleteFlag=true;
try{
//create connection
this.createConnection();
//set autocommit to fals - allows batch commit/rollback
con.setAutoCommit(false);
//create prepare statement from string
delete=con.prepareStatement(deleteRfxItemAttr);
delete.setString(1, orgId);
delete.setString(2, rfxName);
delete.setString(3, rfxUniqueId);
delete.setString(4, revNbr);
//execute prepared statement
delete.execute();
//create prepared statment from string
delete=con.prepareStatement(deleteRfxAttr);
delete.setString(1, orgId);
delete.setString(2, rfxName);
delete.setString(3, rfxUniqueId);
delete.setString(4, revNbr);
//execute prepared statement
delete.execute();
//create prepared statment from string
delete=con.prepareStatement(deleteRfxItem);
delete.setString(1, orgId);
delete.setString(2, rfxName);
delete.setString(3, rfxUniqueId);
delete.setString(4, revNbr);
//execute prepared statement
delete.execute();
//delete parent - create prepared statment from string
delete=con.prepareStatement(deleteUniqueRfxHeader);
delete.setString(1, orgId);
delete.setString(2, rfxName);
delete.setString(3, rfxUniqueId);
delete.setString(4, revNbr);
delete.execute();
catch(Exception e){
deleteFlag=false;
con.rollback();
throw e;
finally {
try {
if(deleteFlag==true){
con.commit();
System.out.println("Comited");
con.setAutoCommit(true);
this.close();
catch (Exception ex) {}
return deleteFlag;
}I don't see anything in the posted code that explicitly suggests that a prepared statement is being used more than once.
More than one prepared statement is being created (and not explicitly closed.) They might or might not produce the same database resource depending on the database/driver or not.
And from the performance perspective, if and only if, the same database resource is being used then there might be some small performance increase. Although I doubt that it is measurable/significant as a database round trip is probably required for each. -
Statement vs PreparedStatements which is better in which situation
Hi i read in a few forums and a few articles that PreparedStatement object performs better than the Statement object in situations where a high number of the same sqls are used because it precompiles the sql statement. such as inserting a 1000 employees into a table.
i did the following test and found that the gain for using PreparedStatements is sometimes not a gain but a loss.
What the test basically does is that it inserts an item into the table a 2000 times using both PreparedStatements and Statement objects. And it switches between which object it uses to insert item into the table. So in the end 1000 items would have been inserted using PreparedStatements and 1000 using Statement objects.
Am i doing somthing wrong with my test or is the so called gain by using PreparedStatements a fluke. Please advise.
import java.sql.*;
public class TEST {
static int Prepcount = 1;
static long PreptotalTime = 0;
static long PrepstartTime = 0;
static long PrependTime = 0;
static long Prepavarage = 0;
static int Stmtcount = 1;
static long StmttotalTime = 0;
static long StmtstartTime = 0;
static long StmtendTime = 0;
static long Stmtavarage = 0;
static PreparedStatement pst;
static Statement stmt;
static ResultSet rs;
static Connection conn;
public static void usePrep() {
try {
pst = conn.prepareStatement("insert into Dhanu values (?,?)");
PrepstartTime = System.currentTimeMillis();
pst.setInt(1, Prepcount);
pst.setInt(2, Prepcount);
pst.executeQuery();
PrependTime = System.currentTimeMillis();
PreptotalTime = PreptotalTime + (PrependTime - PrepstartTime);
Prepavarage = PreptotalTime / Prepcount;
Prepcount++;
pst.close();
} catch (Exception e) {
e.printStackTrace();
public static void useStatement() {
try {
StmtstartTime = System.currentTimeMillis();
stmt = conn.createStatement();
rs = stmt.executeQuery("insert into Dhanu values ("+Stmtcount+","+Stmtcount+")");
StmtendTime = System.currentTimeMillis();
StmttotalTime = StmttotalTime + (StmtendTime - StmtstartTime);
Stmtavarage = StmttotalTime / Stmtcount;
Stmtcount++;
rs.close();
stmt.close();
} catch (Exception e) {
e.printStackTrace();
public static void main(String[] args) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
conn = DriverManager.getConnection("jdbc:oracle:thin:@XXX.XXX.XXX.XXX:1521:XXX", "XXX", "XXX");
System.out.println("Connected to DB");
conn.setAutoCommit(true);
for(int x=1;x<=2000;x++){
if(x%100==0){
System.out.println("Count is "+x);
if(x%2==0){
usePrep();
}else
useStatement();
System.out.println("Prepcount " + Prepcount + " Prepavarage " + Prepavarage + " CurrentExecution " +(PrependTime - PrepstartTime)+ " Totaltime "+PreptotalTime);
System.out.println("Stmtcount " + Stmtcount + " Stmtavarage " + Stmtavarage+ " CurrentExecution " +(StmtendTime - StmtstartTime)+ " Totaltime "+StmttotalTime);
System.err.println("Statement time - Prep Time " + (StmttotalTime - PreptotalTime ));
} catch (Exception ex) {
ex.printStackTrace();
System.exit(0);
}sjasja wrote:
There can still be a performance advantage to PS's even when not used in a loop. Oracle in particular has a textual statement cache. When you execute
insert into foo values(1);
insert into foo values(2);
insert into foo values(3);
the three statements are textually different, so they get re-parsed and the query optimizer runs thrice. But when you prepare
insert into foo values(?);
the parsed and optimized statement remains in the statement cache for some time, and each execution with a different value for "?" can use the pre-parsed statement. The more complex the statement, the bigger the advantage.Yes they do, and so do many others. But it is only that, a cache. It will "usually" be available, not necessarily always. But, in any case, it is still best practice to prepare it, use it multiple times, and close it.
>
I have heard rumors of databases (MSSQL???) where a PS is indeed costlier, as the protocol between the JDBC driver and the DB server requires a separate compilation step. One could argue that in this world, where Java is so important in the server side, and the other advantages of PreparedStatement favor its use, any serious database has had much reason in the last decade to implement a protocol where a separate compilation step is not needed, and any other speed penalties for PSs are decidedly not a marketing advantage.One could argue that, and many have, but PreparedStatements did not spring into being with JDBC, they have existed previously. They are easier to use, however, in Java, and some sort or precompilation is required (even if it is only done the first time the statement is actually run) because at some point in time the DB must determine the paths to take when actually executing the statement, and that was the purpose behind precompiled statements in the first place, so that that determination is done once, and used multiple times. Otherwise it is done as the statement is executed, each time a statement is executed (unless, at least in Oracle, the same statement is still in the statement cache, then it is also reused, rather than redetermined). -
Exception: Call of execute(String) is not allowed for PreparedStatement
Hi all,
This query was run fine on SapDB 7.4 from Jave code using prepareStatement() method:
declare id11216053819634 cursor for select sc.name, measuredobjectid id from serviceconditions sc, measuredobjects mo where sc.collectionid = mo.collectionid and sc.name like 'DWindowsSLA/%,%,%,%' for reuse
declare id21216053819634 cursor for select min(sampletime), max(sampletime), name, id11216053819634.id from id11216053819634, d_slastore ss where id11216053819634.id = ss.measuredobjectid and ss.sampletime between '2008-07-14 00:00:00' and '2008-07-14 12:43:35' group by name, id11216053819634.id for reuse
select ss.status, ss.statuschange, ss.sampletime, id21216053819634.name from d_slastore ss, id21216053819634 where ss.measuredobjectid = id21216053819634.id and ss.sampletime between '2008-07-14 00:00:00' and '2008-07-14 12:43:35' and (statuschange != 0 or ss.sampletime = id21216053819634.expression1 or ss.sampletime = id21216053819634.expression2) order by name, sampletime
We recently upgrade our old SapDb to the latest MaxDB. An now this query produces the error:
com.sap.dbtech.jdbc.exceptions.JDBCDriverException: SAP DBTech JDBC: Call of execute(String) is not allowed for PreparedStatement.
Does anyone know how to fix this?
Thank you very much,
IrinaHi Irina,
First, welcome to SDN!
Well, PreparedStatement represents a precompiled SQL statement, so you should be using the no-arg execute() method rather than execute(String).
HTH!
\-- Vladimir -
Bind Variable reuse in GROUP BY queries
We have several queries that are rather large (in are opinion, that is) and they each have 10 '?' place holders for binding JDBC parameters. These queries also use bind variables in the WHERE and GROUP BY clauses. Eventhough there are 10 bind variable place holders ('?'), there are only 3 distinct values needed.
So...in TOAD or SQL*Plus, we run the queries and "reuse" the same three bind variables and the query works fine. If we use 10 different bind variables, filled with the 3 values, we get a an error, "not a GROUP BY expression."
We would like to make these calls as JDBC PreparedStatements and bind the parameters at run time, so that we could take advantage of the statement cache and increase performance. But...since JDBC parameter binding seems to be positional, we seem to be getting 10 different bind variables at runtime in the PreparedStatement call. Is there a way to "reuse" the bind variables that JDBC is binding at runtime?
Regards,Yep...that is what we are doing. We have a work around that is to manually replace the ? with string data and then pass the query in complete. It will work fine for us. I was just checking the alternatives. The query is large, but the offending code is:
...( select distinct T3.ptcpt_cd,trunc(new_time(T1.start_dt_gmt, 'GMT', ?)) trade_date,
sum(decode(T1.sttl_item_num, 10, T1.sttl_item_qnty, 0)) DA_CHARGE_MW,
sum(decode(T1.sttl_item_num, 10, T1.sttl_item_amt, 0)) DA_CHARGE_AMT,
sum(decode(T1.sttl_item_num, 30, T1.sttl_item_qnty, 0)) BAL_CHARGE_MW,
sum(decode(T1.sttl_item_num, 30, T1.sttl_item_amt, 0)) BAL_CHARGE_AMT,
sum(decode(T1.sttl_item_num, 20, T1.sttl_item_qnty, 0)) DA_CREDIT_MW,
sum(decode(T1.sttl_item_num, 20, T1.sttl_item_amt, 0)) DA_CREDIT_AMT,
sum(decode(T1.sttl_item_num, 40, T1.sttl_item_qnty, 0)) BAL_CREDIT_MW,
sum(decode(T1.sttl_item_num, 40, T1.sttl_item_amt, 0)) BAL_CREDIT_AMT,
T3.source_cd Source
from nm_sttl_item_dtl T1, nm_settlement T2, nm_sttl_statement T3
where trunc(new_time(T1.start_dt_gmt, 'GMT', ?)) between to_date(?,'mm/dd/rrrr') and to_date(?,'mm/dd/rrrr')
and sttl_item_num in (10, 20, 30, 40)
and (sttl_item_qnty <> 0 and sttl_item_amt <> 0)
and T1.sttl_id = T2.sttl_id
and T2.statement_id = T3.statement_id
and T3.ptcpt_cd = 'FAC'
and T3.source_cd = AREA'
group by T3.ptcpt_cd,trunc(new_time(T1.start_dt_gmt, 'GMT', ?)), T3.source_cd)... -
Using PreparedStatement and the Oracle Error ORA-1000
Hi,
I have a question about PreparedStatement objects that is not so simple to explain for me. What I would like to know is: if I use a PreparedStatement following traditional and generic steps:
1- PreparedStatement pStmt = Connection.prepareStatement(sQuery);
2- pStmt.setXXX(i,j);
n - pStmt.setXXX(i,j);
n+1 - ResultSet rs = pStmt.executeQuery();
n+2 - while(rs.next()){ ... retrive ResultSet data ... }
n+3 - rs.close()
n+4 - back to point number 2
and at the end (as you can see in the point numbered n+4), instead of closing the PreparedStatement pStmt using the close() method, I reuse the PreparedStatement pStmt comeing back to the point numebr 2 and setting again all its parameters with new values ... then ... what heppens in the Oracle database ? Has been the cursor (so the mamory area), associated to my PreparedStatement object pStmt, duplicated or is it the same ?
I know that Java allows you to do this kind of operations with PreparedStatement, and I know that in tha Java Documentation is explained to follow this strategy to optimize the execution time because in this way the same PreparedStatement is precompiled and prepared only once. But if I do a for loop following the steps explained before, after many iterations I have the error "ORA-1000: maximum open cursors exceeded". This error is the reason of my question. Does this error means that it's mandatory to close a PreparedStatement always, otherwise if you reuse it without closing it then the corresponding database cursor will be duplicated ? If it is so, then I think this is a contradiction with official java documentation ...
I'm using Oracle8i (version 8.1.7) and Oracle JDBC Thin Driver (Windows NT) for use with JDK 1.2.x. Moreover, in my database istance the parameter "maximum open cursor" is equal to 800 ...
Thank you very much for suggestions :-)There is no need to close a prepared statement or its resultset for every iteration.
After the first iteration in a loop, all subsequent executions of it will close the previous resultset. By adding close() method, you are making one extra costly call to the DB for no reason.
Following is the sample code.I know what you are saying. In fact at the beginning I wrote my code in the same way of your sample (see the code of my first post at the begin of this page).
But doing so, after thousand iterations of the loop, I had "Oracle Error ORA-1000 : maximun open cursor exeeded" even if in my database istance the parameter "maximum open cursor" is equal to 8000.
At this moment in my code, for each iteration, I close the PreparedStatement and in this way I don't have anymore the error :-((
So it seems that only in theory we can reuse a preparedStatement without closing it. In fact if we see the oracle system table "$open_cursor" (as Konrad Pietzka suggest me) we can find that, for each interation,
at our line code "rs = pstmt.executeQuery();" correspond a new cursor in the database: this means that for each method "pstmt.executeQuery()" the database open a new cursor and do not use the previous one as it should.
I posted a question two months ago to search if someone had the same problem (it seems that Konrad Pietzka had the same situation) and was able to explain me what is the cause.
The only reason I found by myself for this problem, is that probably the Oracle JDBC Thin Driver for Windows NT/2000 has some bugs... but I'm not sure ...
Thank you very much for you time !!
bye :-))
Fidalma -
Pooling PreparedStatement s- Connection Pooling in a Servlet-Applicatrion
We are using OC4J (Servlets) and Oracle9i.
In the application I use Connection Pooling with
datasource.xml.
It works fine.
Is it possible to create a pool of PreparedStatements and "connect" them with the connections in the pool?
Has anyone an idea how to do it or an example?
Thanks in advance
PeterIt's not necessarily "bad" as in "it won't work". I personally wouldn't do it because it's poor design. Now, if this is just a small, trivial app. then you have to decide if abstracting things more is worth it. It's not following best practices to put JDBC calls in your servlet. Your servlet should sit there and direct traffic to appropriate handlers, acting as a controller.
At a minimum I would put the JDBC stuff in its own class and have the servlet use that class.
Even if you keep your JDBC stuff in your servlet, you really should reuse a common set of DB connections instead of creating a new one each time. -
Multithreading and PreparedStatement
I am debugging a problem with the interaction between Hibernate and our JDBC driver.
Hibernate uses a PreparedStatement to insert values into the database. When it inserts a Timestamp value into the database, it sets the value into the Timestamp object, calls setTimestamp, and then it uses the same Timestamp object in other threads, setting it to different values, before it calls execute on the PreparedStatement.
My question is, is it valid for an application to assume that the JDBC driver has made a copy of the Timestamp value when it calls setTimestamp, or should it hold off on reusing the Timestamp value until after it has called execute?
To me it seems that the driver should be able to defer all processing of the PreparedStatement parameters until execute(), because the application could call clearParameters, in which case any work done by the JDBC driver would be wasted. This is not so obvious for Timestamp parameters, but what about stream parameters? Clearly the driver is not going to read the stream until execute.I'm not talking about POJO. Think just straight JDBC, inside the guts of Hibernate.
Here is what Hibernate is doing:
Timestamp ts = new Timestamp();
// this one timestamp object is used by multiple threads
<now we have a thread that does this>
PreparedStatement pstmt = connection.prepareStatement("some sql");
ts.setTime(something);
pstmt.setTimestamp(n, ts);
<then, another thread does this:>
PreparedStatement pstmt1 = connection.prepareStatement("some sql");
ts.setTime(something else);
pstmt1.setTimestamp(n1, ts);
<meanwhile, the original thread is doing this>
pstmt.execute();
The JDBC driver only keeps a reference to the timestamp when Hibernate calls setTimestamp(). By the time Hibernate calls execute(), another thread has already picked up this timestamp object and reused it, so it doesn't contain the same value that it did when it called setTimestamp().
It's really horrible when the second thread calls setTime() when the first thread is in the execute() call, in the middle of reading its value to send it to the database, because the first thread reads an inconsistent value from the timstamp object and sends it to the database, which barfs because the inconsistent value ends up being something like Feb. 30. I can get this nightmare to happen pretty regularly on an SMP machine.
My question is: is Hibernate doing something bad by reusing the Timestamp object before calling execute(), or is the JDBC driver at fault for not keeping a copy of the Timestamp object at setTimestamp() time? I have read the JDBC spec over and over again and I can't see an answer to this question. -
PreparedStatement and performance..
<html>
<b> Q1: Increases Network calls?? </b><br>
<p> Where there is a table with large number columns , does a bind call to each column from a middle tier makes a network round-trip to the database?? Or does the Oracle JDBC driver cache binds to all columns and send them over in one call?? </p><br>
<br>
<b> Q2: Is the Statement faster then PreparedStatement for such large tables??</b><br>
<p>If the answer to Q1 is yes, Will the recompilation needed by a Statement with values concatenated as literals in the SQL text beat the combined speed of such numerous bind calls ?? </p><br>
<b> Q3. Recompilation of Statement Vs Oracle SQL Cache </b><br>
<p> Are Q1 and Q2 moot ?? I.e If different values are concatenated to the Statement SQL text, does that in itself force Oracle to treat it as a different SQL or Has Oracle become advanced enough to treat literals as bind values and hence reuse a Statement cursor with diff. literal values executed in the past in the Cache?? </p><br>
<br>
<b> Q4. If Q3 is NO: PreparedStatement VS cached Cursor reuse </b><br>
<p> If the anwser to Q3 is NO - i.e Statment is inefficient, then can we conclude that PreparedStatement offers double advantages. i.e. within the same session multiple executions are faster , since we only rebind. Also if the connection is closed and PreparedStatement is also closed , but the if same PreparedStatement is reopened in a new Session within the near future, Oracle will reuse the Cached statement, since the SQL text with place-holders('?' marks) definitely matches it. Whereas a Statememt with new literal values concatenated in is a new Statement for every new execution??</p><br>
<br>
<b> Q5. Is Q4 moot: PreparedStatement Vs mutiple Sessions </b><br>
<p> Does closing and reopening a PreparedStatement force a recompilation of the statement anyways, so considerations of a cached Statement reuse is not a benefit for performance tuning here??</p><br>
Please reply.
</html>Sorry for the formatting messup:
Q1: Increases Network calls??
Where there is a table with large number columns , does a bind call to each column from a middle tier makes a network round-trip to the database?? Or does the Oracle JDBC driver cache binds to all columns and send them over in one call??
Q2: Is the Statement faster then PreparedStatement for such large tables??
If the answer to Q1 is yes, Will the recompilation needed by a Statement with values concatenated as literals in the SQL text beat the combined speed of such numerous bind calls ??
Q3. Recompilation of Statement Vs Oracle SQL Cache
Are Q1 and Q2 moot ?? I.e If different values are concatenated to the Statement SQL text, does that in itself force Oracle to treat it as a different SQL or Has Oracle become advanced enough to treat literals as bind values and hence reuse a Statement cursor with diff. literal values executed in the past in the Cache??
Q4. If Q3 is NO: PreparedStatement VS cached Cursor reuse
If the anwser to Q3 is NO - i.e Statment is inefficient, then can we conclude that PreparedStatement offers double advantages. i.e. within the same session multiple executions are faster , since we only rebind. Also if the connection is closed and PreparedStatement is also closed , but the if same PreparedStatement is reopened in a new Session within the near future, Oracle will reuse the Cached statement, since the SQL text with place-holders('?' marks) definitely matches it. Whereas a Statememt with new literal values concatenated in is a new Statement for every new execution??
Q5. Is Q4 moot: PreparedStatement Vs mutiple Sessions
Does closing and reopening a PreparedStatement force a recompilation of the statement anyways, so considerations of a cached Statement reuse is not a benefit for performance tuning here??
Please reply. -
Performance Problem - MS SQL 2K and PreparedStatement
Hi all
I am using MS SQL 2k and used PreparedStatement to retrieve data. There is strange and serious performance problem when the PreparedStatement contains "?" and using PreparedStatement.setX() functions to set its value. I have performed the test with the following code.
for (int i = 0; i < 10; i ++) {
try {
con = DBConnection.getInstance();
statement = con.prepareStatement("SELECT * FROM cardno WHERE car_no = '" + cardNo + "'");
// statement = con.prepareStatement("SELECT * FROM cardno WHERE car_no = ?");
// statement.setString(1, cardNo);
rs = statement.executeQuery();
if (rs.next()) {
catch(SQLException e) {
e.printStackTrace();
finally {
try {
rs.close();
statement.close();
catch(SQLException e) {
e.printStackTrace();
Iteration Time (ms)
1 961
10 1061
200 1803
for (int i = 0; i < 10; i ++) {
try {
con = DBConnection.getInstance();
// statement = con.prepareStatement("SELECT * FROM cardno WHERE car_no = '" + cardNo + "'");
statement = con.prepareStatement("SELECT * FROM cardno WHERE car_no = ?");
statement.setString(1, cardNo);
rs = statement.executeQuery();
if (rs.next()) {
catch(SQLException e) {
e.printStackTrace();
finally {
try {
rs.close();
statement.close();
catch(SQLException e) {
e.printStackTrace();
Iteration Time (ms)
1 1171
10 2754
100 18817
200 36443
The above test is performed with DataDirect JDBC 3.0 driver. The one uses ? and setString functions take much longer to execute, which supposed to be faster because of precompilation of the statement.
I have tried different drivers - the one provided by MS, data direct and Sprinta JDBC drivers but all suffer the same problem in different extent. So, I am wondering if MS SQL doesn't support for precompiled statement and no matter what JDBC driver I used I am still having the performance problem. If so, many O/R mappings cannot be used because I believe most of them if not all use the precompiled statement.
Best regards
EdmondEdmond,
Most JDBC drivers for MS SQL (and I think this includes all the drivers you tested) use sp_executesql to execute PreparedStatements. This is a pretty good solution as the driver doesn't have to keep any information about the PreparedStatement locally, the server takes care of all the precompiling and caching. And if the statement isn't already precompiled, this is also taken care of transparently by SQL Server.
The problem with this approach is that all names in the query must be fully qualified. This means that the driver has to parse the query you are submitting and make all names fully qualified (by prepending a db name and schema). This is why creating a PreparedStatement takes so much using these drivers (and why it does so every time you create it, even though it's the same PreparedStatement).
However, the speed advantage of PreparedStatements only becomes visible if you reuse the statement a lot of times.
As about why the PreparedStatement with no placeholder is much faster, I think is because of internal optimisations (maybe the statement is run as a plain statement (?) ).
As a conclusion, if you can reuse the same PreparedStatement, then the performance hit is not so high. Just ignore it. However, if the PreparedStatement is created each time and only used a few times, then you might have a performance issue. In this case I would recommend you try out the jTDS driver ( http://jtds.sourceforge.net ), which uses a completely different approach: temporary stored procedures are created for PreparedStatements. This means that no parsing is done by the driver and PreparedStatement caching is possible (i.e. the next time you are preparing the same statement it will take much less as the previously submitted procedure will be reused).
Alin. -
PreparedStatement objects are compiled and prepared only once by jdbc.
- The future invocation of the PreparedStatement object does not recompile the SQL statements.
What does this statement mean ? Does it mean that incase of Statement objects the query gets compiled each time even if there is no change in the query ? Am just trying to understand the difference between Statement and PreparedStatement.Note that not all JDBC drivers actually implement the pre-compilation feature of PreparedStatements, but that shouldn't really bother you because that feature is transparent to the developer (i.e. you shouldn't notice if it works or not).
If it works, it means that the SQL statement is parsed and interpreted only once and stored in some pre-compiled state to be reused on subsequent invocations.
But in my opinion that is not the most important feature of PreparedStatements. Much more important is the ability to specify values using parameters without having to convert them to the correct SQL string representation. This is the simplest way to protect against [SQL injection attacks|http://en.wikipedia.org/wiki/SQL_injection]. -
Statment used like PreparedStatement
following is the code of a DAO written by one of the team member. He says that PreparedStatements are slower and so he is writing DAO using Statements. For queries which takes dynamic parameters this code uses a StringUtil class to parse queries and replce all '?' with parameters. I am posting StringUtils class with this code. I request you to send suggestions on this design. I feel this will be slower than using PreparedStatement.
//Standard JDK imports
import java.util.Collection;
import java.util.HashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.nate.common.NATEConnection;
import com.nate.common.exception.DAOException;
import com.nate.common.exception.NATEConnectionException;
import com.nate.common.utils.StringUtils;
import com.nate.web.admin.admusrmgmt.vo.AdminMgmtVO;
//3rd Party imports
import org.apache.log4j.Logger;
public class AdminMgmtDAO
private NATEConnection m_nateCon;
private final static String CREATE_ADMIN_QUERY =
"INSERT INTO ADMIN_USER (USER_ID, "
+ "USER_ROLE,CREATE_DATE,USE_YN, USER_PHONE,PASSWORD,"
+ "USER_NAME, HOME_ADDRESS) "
+ "VALUES (?,'admin',sysdate,?,?,?,?,? )";
private static final String FIND_ADMIN_BY_ADMINNAME_QUERY =
"SELECT USE_YN, USER_PHONE, PASSWORD, USER_NAME, "
+ "HOME_ADDRESS FROM ADMIN_USER WHERE USER_NAME=?";
/** Logger, used to log messages */
private Logger m_logger = Logger.getLogger(AdminMgmtDAO.class);
private final static String LS = System.getProperty("line.separator");
public AdminMgmtDAO()
m_nateCon = new NATEConnection();
m_logger.info("NATE Connection object created");
public void createAdmin(AdminMgmtVO vo) throws DAOException
Connection con = null;
Statement stmt = null;
try
//Example using the StringUtils + Statement classes for CUD operation
con = m_nateCon.getConnection();
stmt = con.createStatement();
StringUtils utils = new StringUtils(CREATE_ADMIN_QUERY);
utils.setString(1, vo.getAdminID());
utils.setString(2, vo.getStatus());
utils.setString(3, vo.getMobileNumber());
utils.setString(4, vo.getAdminPassword());
utils.setString(5, vo.getAdminName());
utils.setString(6, vo.getHomeAddress());
String sQuery = StringUtils.getQueryString();
if (m_logger.isInfoEnabled())
StringBuffer sbBuffer = new StringBuffer(50);
sbBuffer.append("Creating Admin user using Query").append(LS);
sbBuffer.append(sQuery).append(LS);
m_logger.info(sbBuffer.toString());
stmt.execute(sQuery);
catch (NATEConnectionException ex)
String strErrMsg =
"[Unable to get the Connection from the NATEConnection Class]";
m_logger.error(strErrMsg, ex);
throw new DAOException(strErrMsg, ex);
catch (SQLException ex)
String strErrMsg = "[Unable to create the Prepared Statment]";
m_logger.error(strErrMsg, ex);
throw new DAOException(strErrMsg, ex);
finally
try
if (stmt != null)
stmt.close();
if (con != null)
con.close();
catch (SQLException ex)
String strErrMsg = "[Unable to close the Resources]";
m_logger.error(strErrMsg, ex);
} //end of createAdmin
public Collection findByAdminName(String adminName) throws DAOException
Connection con = null;
Statement stmt = null;
ResultSet rSet = null;
AdminMgmtVO vo = null;
Collection result = null; //result sent to client
//Example using the StringUtils + Statement classes for Read operation
try
con = m_nateCon.getConnection();
stmt = con.createStatement();
StringUtils utils = new StringUtils(FIND_ADMIN_BY_ADMINNAME_QUERY);
utils.setString(1, "%" + adminName + "%");
String sQuery = StringUtils.getQueryString();
if (m_logger.isInfoEnabled())
m_logger.info(
"Query performing search :" + sQuery);
rSet = pStmt.executeQuery();
while (rSet.next())
if (result == null)
result = new ArrayList();
vo = new AdminMgmtVO();
vo.setStatus(rSet.getString("USE_YN"));
vo.setMobileNumber(rSet.getString("USER_PHONE"));
vo.setAdminPassword(rSet.getString("PASSWORD"));
vo.setAdminName(rSet.getString("USER_NAME"));
vo.setHomeAddress(rSet.getString("HOME_ADDRESS"));
result.add(vo);
vo = null;
catch (NATEConnectionException e)
String strErrMsg =
"[Unable to get the Connection from the NATEConnection Class]";
m_logger.error(strErrMsg, e);
throw new DAOException(strErrMsg, e);
catch (SQLException e)
String strErrMsg = "[Unable to create the Prepared Statment]";
m_logger.error(strErrMsg, e);
throw new DAOException(strErrMsg, e);
finally
try
if (rSet != null)
rSet.close();
if (stmt != null)
stmt.close();
if (con != null)
con.close();
catch (SQLException e)
String strErrMsg = "[Unable to close the Resources]";
m_logger.error(strErrMsg, e);
return result;
} //end of findByAdminName
} //end of class
package com.nate.common.utils;
import com.nate.common.utils.exception.NotEnoughArgumentsException;
import com.nate.common.utils.exception.TooManyArgumentsException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StringUtils
public StringUtils(String s)
m_sQueryStr = s;
parseString(m_sQueryStr);
m_argMap = new HashMap();
public String replaceAll(String s, String s1, String s2)
String s3 = s;
Pattern pattern = Pattern.compile(s1);
Matcher matcher = pattern.matcher(s3);
return matcher.replaceAll(s2);
public void setString(int i, String s)
throws IllegalArgumentException
if(i > m_map.size())
throw new IllegalArgumentException();
int j = s.indexOf("'");
String s1;
if(j > 0)
s1 = replaceAll(s, "'", "''");
else
s1 = s;
m_argMap.put(new Integer(i), s1);
public void setInt(int i, int j)
throws IllegalArgumentException
if(i > m_map.size())
throw new IllegalArgumentException();
} else
m_argMap.put(new Integer(i), String.valueOf(j));
return;
public void setLong(int i, int j)
throws IllegalArgumentException
if(i > m_map.size())
throw new IllegalArgumentException();
} else
m_argMap.put(new Integer(i), String.valueOf(j));
return;
private void parseString(String s)
int i = 0;
int j = 0;
for(i++; i < s.length(); i++)
char c = s.charAt(i);
if(c != '?')
continue;
if(m_map == null)
m_map = new HashMap();
m_map.put(new Integer(++j), new Integer(i));
public void clearParameters()
m_argMap.clear();
public StringBuffer getQueryString()
throws NotEnoughArgumentsException, TooManyArgumentsException
StringBuffer stringbuffer = new StringBuffer();
int i = m_map.size();
int j = m_argMap.size();
if(j < i)
throw new NotEnoughArgumentsException();
if(j > i)
throw new TooManyArgumentsException();
int k = 0;
for(int l = 1; l < i + 1; l++)
int i1 = ((Integer)m_map.get(new Integer(l))).intValue();
stringbuffer.append(m_sQueryStr.substring(k, i1));
stringbuffer.append("'");
stringbuffer.append(m_argMap.get(new Integer(l)));
stringbuffer.append("'");
k = ++i1;
if(k < m_sQueryStr.length())
stringbuffer.append(m_sQueryStr.substring(k, m_sQueryStr.length()));
return stringbuffer;
public static void main(String args[])
StringUtils stringutils = new StringUtils("INSERT INTO ADMIN_USER (USER_ID, USER_ROLE,CREATE_DATE,USE_YN, AGE) VALUES (?,'admin',sysdate,?,?)");
stringutils.setString(1, "test");
stringutils.setString(2, "Y");
stringutils.setInt(3, 25);
System.out.println(stringutils.getQueryString());
stringutils.clearParameters();
stringutils.setString(1, "abc'd");
stringutils.setString(2, "N");
stringutils.setInt(3, 30);
System.out.println(stringutils.getQueryString());
stringutils.setString(1, "%xyz%");
System.out.println(stringutils.getQueryString());
private String m_sQueryStr;
private Map m_map;
private Map m_argMap;
}As you noticed, the order in which you measure Statement and PreparedStatement matters. This is because all the JDBC driver libraries and standard JDK classes get JIT compiled at the start of the run. The timings are not showing the speed of your code, they are showing the speed of JIT compilation.
When doing microbenchmarking, run the measured code several times in a loop. The first few loops are likely to be slower as the JIT compiler is running; then timings more or less settle.
Below is a simple comparision of Statement and PreparedStatement. I won't keep you in suspense: there is no difference under Oracle. "PS's are slow" is a myth.
Other database servers may differ, so if you are executing lots of small SQL statements in tight time-critical loops, benchmark first, then decide which type of statement to use. (PS's most likely, because you can keep them open and re-use them.)
If you have big SQL statements, ask yourself: does the difference between a Statement and a PS really matter? If the db server takes a second to execute the query, and the difference is a few milliseconds, wasting time optimizing it is really silly. Especially given the convenience, safety, and portability of not having to do string quoting and date/time formatting yourself.
// java demo jdbc:oracle:thin:@dbserver:port:dbname username password
import java.sql.DriverManager;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class demo
static Connection connection;
static int ROUNDS = 100;
public static void main(String args[])
try {
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
connection = DriverManager.getConnection(args[0], args[1], args[2]);
long best;
best = -1;
for (int n = 0; n < 10; n++) {
long time = staticStatement();
if (best == -1 || time < best)
best = time;
System.out.println("best time " + best);
best = -1;
for (int n = 0; n < 10; n++) {
long time = staticPrepared();
if (best == -1 || time < best)
best = time;
System.out.println("best time " + best);
best = -1;
for (int n = 0; n < 10; n++) {
long time = plainStatement();
if (best == -1 || time < best)
best = time;
System.out.println("best time " + best);
best = -1;
for (int n = 0; n < 10; n++) {
long time = plainPrepared();
if (best == -1 || time < best)
best = time;
System.out.println("best time " + best);
best = -1;
for (int n = 0; n < 10; n++) {
long time = reuseStatement();
if (best == -1 || time < best)
best = time;
System.out.println("best time " + best);
best = -1;
for (int n = 0; n < 10; n++) {
long time = reusePrepared();
if (best == -1 || time < best)
best = time;
System.out.println("best time " + best);
} catch (Exception e) {
System.err.println("exception in db test: " + e);
e.printStackTrace(System.err);
private static long staticStatement()
throws SQLException
long start_time = System.currentTimeMillis();
for (int n = 0; n < ROUNDS; n++) {
String sql = "select 42 from dual";
Statement stmt = connection.createStatement();
ResultSet res = stmt.executeQuery(sql);
while (res.next()) {
int result = res.getInt(1);
Util.close(res);
Util.close(stmt);
long end_time = System.currentTimeMillis();
long time = end_time - start_time;
System.out.println("static statement: " + time + " ms");
return time;
private static long staticPrepared()
throws SQLException
long start_time = System.currentTimeMillis();
for (int n = 0; n < ROUNDS; n++) {
String sql = "select 42 from dual";
PreparedStatement stmt = connection.prepareStatement(sql);
ResultSet res = stmt.executeQuery();
while (res.next()) {
int result = res.getInt(1);
Util.close(res);
Util.close(stmt);
long end_time = System.currentTimeMillis();
long time = end_time - start_time;
System.out.println("static prepared: " + time + " ms");
return time;
private static long plainStatement()
throws SQLException
long start_time = System.currentTimeMillis();
for (int n = 0; n < ROUNDS; n++) {
String sql = "select " + n + " from dual";
Statement stmt = connection.createStatement();
ResultSet res = stmt.executeQuery(sql);
while (res.next()) {
int result = res.getInt(1);
Util.close(res);
Util.close(stmt);
long end_time = System.currentTimeMillis();
long time = end_time - start_time;
System.out.println("plain statement: " + time + " ms");
return time;
private static long plainPrepared()
throws SQLException
long start_time = System.currentTimeMillis();
for (int n = 0; n < ROUNDS; n++) {
String sql = "select ? from dual";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setInt(1, n);
ResultSet res = stmt.executeQuery();
while (res.next()) {
int result = res.getInt(1);
Util.close(res);
Util.close(stmt);
long end_time = System.currentTimeMillis();
long time = end_time - start_time;
System.out.println("plain prepared: " + time + " ms");
return time;
private static long reuseStatement()
throws SQLException
long start_time = System.currentTimeMillis();
Statement stmt = connection.createStatement();
for (int n = 0; n < ROUNDS; n++) {
String sql = "select " + n + " from dual";
ResultSet res = stmt.executeQuery(sql);
while (res.next()) {
int result = res.getInt(1);
Util.close(res);
Util.close(stmt);
long end_time = System.currentTimeMillis();
long time = end_time - start_time;
System.out.println("reuse statement: " + time + " ms");
return time;
private static long reusePrepared()
throws SQLException
long start_time = System.currentTimeMillis();
String sql = "select ? from dual";
PreparedStatement stmt = connection.prepareStatement(sql);
for (int n = 0; n < ROUNDS; n++) {
stmt.setInt(1, n);
ResultSet res = stmt.executeQuery();
while (res.next()) {
int result = res.getInt(1);
Util.close(res);
Util.close(stmt);
long end_time = System.currentTimeMillis();
long time = end_time - start_time;
System.out.println("reuse prepared: " + time + " ms");
return time;
public static class Util
public static void close(Statement s)
if (s == null)
return;
try {
s.close();
} catch (Exception e) {
System.err.println("Util.close: error closing Statement: " + e);
public static void close(ResultSet s)
if (s == null)
return;
try {
s.close();
} catch (Exception e) {
System.err.println("Util.close: error closing ResultSet: " + e); -
Statement vs PreparedStatement
Can anyone offer guidelines ( or point me to documentation) which describes when/why use a
Statement as opposed to a PreparedStatement.
I realize that a PreparedStatement can be defined with Bind variables for later substitution and thus the statement gets compiled only once thereby being more efficient.
But is that the only difference ? does it make sense to use a PreparedStatement even if there are no Bind variables ?Whenever you want to re-use a statement you should use Statement and not PreparedStatement.
Statements can effectively only be used once, since you provide the SQL text to the execute method: this means that when issuing execute (or executeQuery) the statement is always fully reparsed by the database.
If you have a PreparedStatement object, you can re-execute it, and the database will reuse the parsed statement.
Maybe you are looking for
-
Hi, I have a table with two columns as follows child parent mom grandma daughter mom How can I write a single query so that the result will be daughter,mom,grandma? Thanks Ravi.
-
ADF application deployed to Weblogic producing runtime error
Hi all, We are trying to deploy a new ADF application built by JDeveloper 11.1.1.5.0 to a standalone weblogic (*version 10.3.1.0*) The app deploys and runs on integrated wls without any problems, and deploys to the standalone wls without any warnings
-
Recently I am unable to play AVI videos on quicktime that I have never had any problems playing before, the thumbnails of the clips also don't display. Has there been some change to Quicktime as there was never an issue since I've had my macbook pro
-
Letter of credit maintenance for order and delivery documents
Hi Friends, As there are three places where we can maintain Letter of Credit ( Financial documents) data.as 1. Order Header data 2. Order Item data 3. Delivery Header data What is the importance of all these and ideally where shd maintain ? kindly gu
-
Output log to application log in application server
Hi Guys, I am pretty new on J2EE, I created a web application and deployed it on to the oracle application server. I found out that I can view the log file(application.log) for that particular web application on the application control page. What I w