Will PreparedStatement without bind variable affect performance? - java

Does performance will be less if I will not use bind variables in prepared statements.
Consider the example below:
String selectSQL = "SELECT USER_ID, USERNAME FROM DBUSER WHERE USER_ID = '101'";
PreparedStatement preparedStatement = dbConnection.prepareStatement(selectSQL);
below one is preferable I know.
it prevents sql injection
String selectSQL = "SELECT USER_ID, USERNAME FROM DBUSER WHERE USER_ID = ?";
this question asked because one of my project in all the queries they have hard coded string literals even they are using prepared statements.

A prepared statement just means you "prepare" the statement. This means you sent it to the database and let the database already parse/compile the statement. This is useful for statements which are executed often.
Parameterised statements are often executed many times so they are sometimes associated with prepared statements (you only have to send the values across and the server will have an already compiled statement ready to execute the query).
But even with a "static" statement which is executed often you might benefit from preparing the statement (especially for "complex" statements). Another technique used is to implement the query inside a a stored procedure. That way the query is already compiled and the server only needs to compile the stored procedure call when you run it.
It will only work if you don't unprepare the stamenent (e.g, when closing the connection). So you might need a pool and a prepared statement cache to not overflow the server with prepared statement request (prepared statements require resources on the server's end)
Parameterised queries are also used to protect against sql-injection (as it is based on data types and not strings). However this is orthogonal to the benefits of prepared statements. (Note both your queries are not exposed to sql injection)

Whether or not using parameters is more efficient mainly depends on your use case. When you monitor the times spent in preparation and execution of statements, you will notice, that preparation of statements is somtimes siginificantly more expensive than the actual execution, so it depends, whether you can save on prepares.
You will always win in a scenario like this:
PreparedStatement stmt = dbConnection.prepareStatement(...);
stmt.setInt(1, x);
stmt.executeQuery();
...
stmt.setInt(1, y);
stmt.executeQuery();
...
because you save on the prepare-times. This is DBMS independent.
Some DBMS do some server side caching. What and how they do it is highly vendor and even version-specific. However, we have learned that in Oracle-DBMS parametrised statements which are used more often do sometimes get quite a speed-up in such a scenario:
PreparedStatement stmt = dbConnection.prepareStatement(...);
stmt.setInt(1, x);
stmt.executeQuery();
...
PreparedStatement stmt2 = dbConnection.prepareStatement(...);
stmt2.setInt(1, y);
stmt2.executeQuery();
...
Here the server is able to identify that both statements are essentially the same and prepare-times for the second statement were significantly reduced. This does not work for fixed-string statements because the server cannot determine, they are the same.
I don't think, you will find a scenario, where using parametrized statements are measurable slower than fixed-string-statements but a lot of scenarios, where its the other way around.

Related

Java - to - sql statement, variables in Insert into vs setString

What is the difference between these two statements, do they both work the same way, or does the first one work at all? Can I use variables after "Insert into"?
stmt = conn.prepareStatement("INSERT INTO treatment(CPR,Treatment,ID,TreatedOn) "+
"VALUES("+Cpr+Id+date.toString());
Where id, cpr are a string,int or other variable, bin my case it is a string,
PreparedStatement insertStatement;
insertStatement = connection.prepareStatement("INSERT INTO sep2.movies(title,length) "
+ "VALUES (?,?,?)");
insertStatement.setString(1, Title);
insertStatement.setInt(2, movie.getLength());
where Title is a string and getLength returns an int.
Which one of these should I use ?
I understand what setString does but do I have to use it?
Also I am inserting only elementary/non-object data types into Treatment. Does it make a difference? (I am using postgres if that matters)
And other important aspect of using bind variables, is that it improves the performance of the application. When you use bind variables, database server cache and optimize the query and improve the performance (respect to time and processing) of your application.
For example,
When you use
insertStatement = connection.prepareStatement("INSERT INTO sep2.movies(title,length) "
+ "VALUES (?,?,?)");
insertStatement.setString(1, Title);
insertStatement.setInt(2, movie.getLength());
The statement is cashed inside database server and only the parameters are bind in the run time inside the database. This will improve performance significantly.
you can read Designing applications for performance and scalability An Oracle White Paper
http://www.oracle.com/technetwork/database/performance/designing-applications-for-performa-131870.pdf
It is always a good practice that applications that execute SQL commands should neutralize any externally-provided values used in those commands. Failing in doing so could allow an attacker to include input that changes the query so that unintended commands are executed, or sensitive data is exposed (SQL Injection).
The first example (string concatenation) is not safe, because it is vulnerable to SQL Injection since malicious data can be concatenated to the query itself (not to mention that it can lead to syntax errors, etc).
The second case (where method such as PreparedStatement#setString are used) correctly uses parameterized queries by utilizing Java's PreparedStatement class, bind variables and the corresponding setString methods. Thus SQL Injection can be easily prevented (avoiding other problems such as the mentioned syntax errors).
Further readings:
How does a PreparedStatement avoid or prevent SQL injection?
Prepared Statements (with Parameterized Queries)

Difference about performance betwen Named parameters and Positional parameters

I know that comparing with a normal Select, putting the values directly into the SQL statements, like this way:
Statement command = connection.createStatement( "SELECT * FROM person WHERE name = "+ nameVar);
Doing that with JDBC and positional parameters, like this:
String statment= "SELECT * from Users WHERE name=? and pass =?";
sentence = conexion.prepareStatement(consulta);
sentence.setString(1, nameVar);
sentence.setString(2, passVar);
Is better for several things, like avoid SQL injection, and also uses less memory (for caching the execution plan only once) and performance (for not doing the same execution plan again and again)
But if you have a lots of "?" may be difficult to correlate the parameter with the variable, and that can cause an error.
My question is, if there is a difference between doing the positional parameters as above with doing "named parameters" like this:
String statment= "SELECT * from Users WHERE name=:nameParam and pass =:passParam";
sentence = conexion.prepareStatement(consulta);
sentence.setString("nameParam", nameVar);
sentence.setString("passParam", passVar);
Because is easier and can skip errors
UPDATE
by the comments seems that only using JPA/Hibernate can use :parameters. Well The question remains. There is any difference using Hibernate?
As you point out you are building a PreparedStatement so that the DB can cache it's execution plan etc. So that is where all the performance gain comes from when the driver actually talks to the DB.
The other benefits are for the code. It is DRY-er (Do not Repeat Yourself) you can prevent SQL injection attacks as you can validate the params and they can't add "structural changes" to the SQL. You can keep a ref to the PreparedStatement Object so no need to re-create it etc etc.
But you are doing this on both cases, so the main benefits are the same. Under the covers an Array of params is passed to the Driver to run the prepared statement.
Positional params will most likely just index into the Array (depending on your Drivers' implementation) whereas named params maintain a map of name to position and generate the correct array when required.
Given that the number of params in a SQL statement tends to be small (can usually count them on one or two hands) creating the array is very fast, and negligible compared to the cost of running the query over the network to the DB.
So IMHO use whichever helps you reason about your code best. The performance difference is minuscule.

Concatenation in prepared statement

I have written universal DAO layer for mySQL (it can save\get any class object that extends Entity to\from table using Reflection and ResultSetMetaData). My implementation of it has little concatenation in sql query. Is it waste all advantages of prepared statement or I just loose little perfomance to concat String and nothing more?
For example piece of code for entity deletion:
PreparedStatement prepStatement = con.prepareStatement("DELETE FROM "
+ tableName + " WHERE id = ?");
prepStatement.setLong(1, id);
The main benefit of PreparedStatements is when you have code that behaves in a similar way to this pseudocode:
PreparedStatement ps = con.prepareStatement("blabalblabla");
for (int i = 0; i < a gazillion times; i++) {
// Set parameters into ps
...
// execute already prepared statement
ps.execute();
}
That is, you prepare once and execute many times, each time with different sets of parameters. This allows the driver / database to perform potentially costly operations (such as parsing) only once and then reuse that work. Apart from that, using PreparedStatement may be interpreted as a hint to the driver that it should cache that statement resources or something because it is going to be used later, but I don't think it will have as much impact as the "prepare once execute many" approach.
Your use of concatenation to add the table names won't disable the optimizations that your JDBC driver does (if any). But anyway, if your code does more of "prepare once execute once" than it does "prepare once execute many", then PreparedStatement might only have a minor performance benefit.
Note that all of the above is highly database / driver dependent. For example, Oracle performs a lot better if you use PreparedStatements in the way I have described as "prepare once execute many". And as a last advice, don't forget that you should avoid concatenating parameter values unless you have no other option, for both performance AND SECURITY reasons.
It's recommended to use the prepared statements for the DB performance improvement.
In theory the DB drivers cache the prepared statements (you might require to enable the caching on connection object).
I would assume that concatenation is not as critical.
Keep in mind that tableName might be case sensitive in the driver cache.
I would review your DB driver features, and you should be able to debug the driver, and monitor the database to see how your statements are handled/executed.
The variable tableName in your example may introduce vulnerability for SQL injection but it may be alternative ways to protect against this. For instance,
Map<String,String> myTables; // key and value are the same.
tableName = myTables.get(tableName); // safe known value or null.
Generally, it is better just to use prepared statements consistently to stay away out of trouble. However sometimes building query (most often where query) "on the fly" can save many lines otherwise close to duplicate code so it is difficult to say "never do this".

Should I use Prepared Statement for inserting one row?

I just found that there are places in our code that use Prepared Statement even though we always deal with inserting one row to the table.
I'm wondering if using Prepared Statement when only inserting one row has some overhead that worth modifying this code to use Statement.
When you use PreparedStement, not just your query execution is faster there are other advantages too.
You queries execute fast as PreparedStatement results into the query being precompiled on the database and reused.
PreparedStatement, your queries are dynamic. Meaning, you define the query only once, and reuse the same again with different parameters. String concatenation also achieves it but its crude way doing this. Quoting this link
The important thing to remember is to never construct SQL statements
using string concatenation of unchecked input values. Creating of
dynamic queries via the java.sql.Statement class leads to SQL
Injection.
When you use PreparedStatement you prevent the SQL injection attacks. In Prepared statement, you do not use string concatenation for adding the runtime parameters but instead set the parameter explicitly in the compiled query and the parameters passed are escaped automatically by JDBC Driver for PreparedStatement.
On the security side, Prepared Statements are used especially to prevent SQL Injection attacks. About efficiency, it very much depends on the nature of the statement you are dealing with. You may also find interesting this other answer:
Why PreparedStatement is preferable over Statement
A PreparedStatement is prefrable to a simple Statement as it offes your some security against SQL injection.
In a PreparedStatement every parameter is checked for its type and automatically escaped. This means that inserting String with an ' is save with PreparedStatement whereas you have to escape special characters yourself when not using a PreparedStatement.
Also you cannot insert some String where a Number is expected.
If even your code inserts only one row it may be called many times in which case PreparedStatement is supposed to be faster. As for Statement it also needs to be compiled before execution so it's hardly be any faster

Difference between Statement and PreparedStatement

The Prepared Statement is a slightly more powerful version of a Statement, and should always be at least as quick and easy to handle as a Statement.
The Prepared Statement may be parametrized
Most relational databases handles a JDBC / SQL query in four steps:
Parse the incoming SQL query
Compile the SQL query
Plan/optimize the data acquisition path
Execute the optimized query / acquire and return data
A Statement will always proceed through the four steps above for each SQL query sent to the database. A Prepared Statement pre-executes steps (1) - (3) in the execution process above. Thus, when creating a Prepared Statement some pre-optimization is performed immediately. The effect is to lessen the load on the database engine at execution time.
Now my question is this:
"Is there any other advantage of using Prepared Statement?"
Advantages of a PreparedStatement:
Precompilation and DB-side caching of the SQL statement leads to overall faster execution and the ability to reuse the same SQL statement in batches.
Automatic prevention of SQL injection attacks by builtin escaping of quotes and other special characters. Note that this requires that you use any of the PreparedStatement setXxx() methods to set the values
preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
preparedStatement.setString(1, person.getName());
preparedStatement.setString(2, person.getEmail());
preparedStatement.setTimestamp(3, new Timestamp(person.getBirthdate().getTime()));
preparedStatement.setBinaryStream(4, person.getPhoto());
preparedStatement.executeUpdate();
and thus don't inline the values in the SQL string by string-concatenating.
preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email) VALUES ('" + person.getName() + "', '" + person.getEmail() + "'");
preparedStatement.executeUpdate();
Eases setting of non-standard Java objects in a SQL string, e.g. Date, Time, Timestamp, BigDecimal, InputStream (Blob) and Reader (Clob). On most of those types you can't "just" do a toString() as you would do in a simple Statement. You could even refactor it all to using PreparedStatement#setObject() inside a loop as demonstrated in the utility method below:
public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
for (int i = 0; i < values.length; i++) {
preparedStatement.setObject(i + 1, values[i]);
}
}
Which can be used as below:
preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)");
setValues(preparedStatement, person.getName(), person.getEmail(), new Timestamp(person.getBirthdate().getTime()), person.getPhoto());
preparedStatement.executeUpdate();
They are pre-compiled (once), so faster for repeated execution of dynamic SQL (where parameters change)
Database statement caching boosts DB execution performance
Databases store caches of execution plans for previously executed statements. This allows the database engine to reuse the plans for statements that have been executed previously. Because PreparedStatement uses parameters, each time it is executed it appears as the same SQL, the database can reuse the previous access plan, reducing processing. Statements "inline" the parameters into the SQL string and so do not appear as the same SQL to the DB, preventing cache usage.
Binary communications protocol means less bandwidth and faster comms calls to DB server
Prepared statements are normally executed through a non-SQL binary protocol. This means that there is less data in the packets, so communications to the server is faster. As a rule of thumb network operations are an order of magnitude slower than disk operations which are an order of magnitude slower than in-memory CPU operations. Hence, any reduction in amount of data sent over the network will have a good effect on overall performance.
They protect against SQL injection, by escaping text for all the parameter values provided.
They provide stronger separation between the query code and the parameter values (compared to concatenated SQL strings), boosting readability and helping code maintainers quickly understand inputs and outputs of the query.
In java, can call getMetadata() and getParameterMetadata() to reflect on the result set fields and the parameter fields, respectively
In java, intelligently accepts java objects as parameter types via setObject, setBoolean, setByte, setDate, setDouble, setDouble, setFloat, setInt, setLong, setShort, setTime, setTimestamp - it converts into JDBC type format that is comprehendible to DB (not just toString() format).
In java, accepts SQL ARRAYs, as parameter type via setArray method
In java, accepts CLOBs, BLOBs, OutputStreams and Readers as parameter "feeds" via setClob/setNClob, setBlob, setBinaryStream, setCharacterStream/setAsciiStream/setNCharacterStream methods, respectively
In java, allows DB-specific values to be set for SQL DATALINK, SQL ROWID, SQL XML, and NULL via setURL, setRowId, setSQLXML ans setNull methods
In java, inherits all methods from Statement. It inherits the addBatch method, and additionally allows a set of parameter values to be added to match the set of batched SQL commands via addBatch method.
In java, a special type of PreparedStatement (the subclass CallableStatement) allows stored procedures to be executed - supporting high performance, encapsulation, procedural programming and SQL, DB administration/maintenance/tweaking of logic, and use of proprietary DB logic & features
PreparedStatement is a very good defense (but not foolproof) in preventing SQL injection attacks. Binding parameter values is a good way to guarding against "little Bobby Tables" making an unwanted visit.
Some of the benefits of PreparedStatement over Statement are:
PreparedStatement helps us in preventing SQL injection attacks because it automatically escapes the special characters.
PreparedStatement allows us to execute dynamic queries with parameter inputs.
PreparedStatement provides different types of setter methods to set the input parameters for the query.
PreparedStatement is faster than Statement. It becomes more visible when we reuse the PreparedStatement or use it’s batch processing methods for executing multiple queries.
PreparedStatement helps us in writing object Oriented code with setter methods whereas with Statement we have to use String Concatenation to create the query. If there are multiple parameters to set, writing Query using String concatenation looks very ugly and error prone.
Read more about SQL injection issue at http://www.journaldev.com/2489/jdbc-statement-vs-preparedstatement-sql-injection-example
nothing much to add,
1 - if you want to execute a query in a loop (more than 1 time), prepared statement can be faster, because of optimization that you mentioned.
2 - parameterized query is a good way to avoid SQL Injection. Parameterized querys are only available in PreparedStatement.
Statement is static and prepared statement is dynamic.
Statement is suitable for DDL and prepared statment for DML.
Statement is slower while prepared statement is faster.
more differences (archived)
Can't do CLOBs in a Statement.
And: (OraclePreparedStatement) ps
As Quoted by mattjames
The use of a Statement in JDBC should be 100% localized to being used
for DDL (ALTER, CREATE, GRANT, etc) as these are the only statement
types that cannot accept BIND VARIABLES. PreparedStatements or
CallableStatements should be used for EVERY OTHER type of statement
(DML, Queries). As these are the statement types that accept bind
variables.
This is a fact, a rule, a law -- use prepared statements EVERYWHERE.
Use STATEMENTS almost no where.
Statement will be used for executing static SQL statements and it can't accept input parameters.
PreparedStatement will be used for executing SQL statements many times dynamically. It will accept input parameters.
sql injection is ignored by prepared statement so security is increase in prepared statement
It's easier to read
You can easily make the query string a constant
Statement interface executes static SQL statements without parameters
PreparedStatement interface (extending Statement) executes a precompiled SQL statement with/without parameters
Efficient for repeated executions
It is precompiled so it's faster
Another characteristic of Prepared or Parameterized Query: Reference taken from this article.
This statement is one of features of the database system in which same SQL statement executes repeatedly with high efficiency. The prepared statements are one kind of the Template and used by application with different parameters.
The statement template is prepared and sent to the database system and database system perform parsing, compiling and optimization on this template and store without executing it.
Some of parameter like, where clause is not passed during template creation later application, send these parameters to the database system and database system use template of SQL Statement and executes as per request.
Prepared statements are very useful against SQL Injection because the application can prepare parameter using different techniques and protocols.
When the number of data is increasing and indexes are changing frequently at that time Prepared Statements might be fail because in this situation require a new query plan.
Dont get confusion : simply remember
Statement is used for static queries like DDLs i.e. create,drop,alter and prepareStatement is used for dynamic queries i.e. DML query.
In Statement, the query is not precompiled while in prepareStatement query is precompiled, because of this prepareStatement is time efficient.
prepareStatement takes argument at the time of creation while Statement does not take arguments.
For Example if you want to create table and insert element then ::
Create table (static) by using Statement and Insert element (dynamic)by using prepareStatement.
I followed all the answers of this question to change a working legacy code using - Statement ( but having SQL Injections ) to a solution using PreparedStatement with a much slower code because of poor understanding of semantics around Statement.addBatch(String sql) & PreparedStatement.addBatch().
So I am listing my scenario here so others don't make same mistake.
My scenario was
Statement statement = connection.createStatement();
for (Object object : objectList) {
//Create a query which would be different for each object
// Add this query to statement for batch using - statement.addBatch(query);
}
statement.executeBatch();
So in above code , I had thousands of different queries, all added to same statement and this code worked faster because statements not being cached was good & this code executed rarely in the app.
Now to fix SQL Injections, I changed this code to ,
List<PreparedStatement> pStatements = new ArrayList<>();
for (Object object : objectList) {
//Create a query which would be different for each object
PreparedStatement pStatement =connection.prepareStatement(query);
// This query can't be added to batch because its a different query so I used list.
//Set parameter to pStatement using object
pStatements.add(pStatement);
}// Object loop
// In place of statement.executeBatch(); , I had to loop around the list & execute each update separately
for (PreparedStatement ps : pStatements) {
ps.executeUpdate();
}
So you see, I started creating thousands of PreparedStatement objects & then eventually not able to utilize batching because my scenario demanded that - there are thousands of UPDATE or INSERT queries & all of these queries happen to be different.
Fixing SQL injection was mandatory at no cost of performance degradation and I don't think that it is possible with PreparedStatement in this scenario.
Also, when you use inbuilt batching facility, you have to worry about closing only one Statement but with this List approach, you need to close statement before reuse , Reusing a PreparedStatement

Categories