Is there a point to use prepared statement when you just want to select all rows in a table? There are notning to bind compared if you used WHERE name = ? in the query.
$stmt->prepare("SELECT * FROM countries ORDER BY name");
Is it better to use the MySQLi without Prepared Statements like
$sql = "SELECT * FROM countries ORDER BY name";
Prepared statements are preferable to plain SQL queries when you are using parameters to dynamically generate the query. In your example, your SQL contains no variables, so using a plain query or prepared statement are functionally equivalent.
Prepared Statements
To answer your question directly, no. And in many languages the prepared statement library wouldn't even work with a query like that due to the method signatures of that library. I am going to give a background of prepare statements and database management systems because they are both essential to understanding the efficiencies generated by prepared statements.
Queries and Database's
When you execute a statement in any database management systems you trigger an execution of steps. At a very high level the database management system does the following things.
Query is received by the DBMS
SQL is interpreted
Query parsing
Query optimization
Resultset returned
Prepared Statements and Database's
A prepared statement is similar to any other SQL query issued to a database management system except with a few caveats.
First, a prepared statement template (without parametic values) is sent to the database management system from the application. After interpreting the SQL the database system then begins query parsing and query optimization where it validates the syntax and semantics, and begins the process of finding the best query plan, respectively.
A query plan is a set of executions used to run the supplied query. In most cases a query can have multiple query planes. It is part of the database management system to pick the most efficient plane.
Query optimizer continues to generate a variety of query plans and assigned then a cost and a value.
This process so far is mostly the same for both prepared statements and regular statements.
So to understand why your query would not benefit from being a prepared statement (besides the fact that prepared statements are defined as necessarily having parameters), let's take a closer look into the prepared statement optimization.
Optimizing
We stayed before that the query optimizer picks from a list of query plans for the most efficient one. However, we didn't discuss how it actually does this. For a non parametic statement the optimizer assign each plan a scalar cost value.
However, for a parametic query the optimizer associates each query plant to a function that maps multi dimensional parameter space to cost space, respectively. Basic to get all optimal queries for any given input.
This is a costly process, however on successive runs is very quick because the answer is known instead of calculates.
.
Related
Looking at thegeneral MySQL log, when I use mysqli with parameterized queries with PHP I see statements like this:
Prepare SELECT * FROM my_table WHERE id = ?
Execute SELECT * FROM my_table WHERE id = 9
Prepare INSERT INTO my_table SET name = ?
Execute INSERT INTO my_table SET name = 'Alex'
This makes me feel warm and fuzzy, because I distinctly see that first, my query was sent, and them, my parameters, in two separate statements.
But when using an ORM (Doctrine in this case), I see the following:
Query SELECT t0.id AS id_1, t0.name AS name_2 FROM my_table t0 WHERE t0.id = '9'
Query START TRANSACTION
Query INSERT INTO my_table (name) VALUES ('Alex')
Query COMMIT
This has me feel alerted, as I do not see the same sequence of statement being send followed by parameters. It's statement + parameters in one go.
Questions about this that I have are:
Is Doctrine actually using parameterized statements, and why doesn't it do what MySQL does - log two packets, like mysqli does natively?
Is Doctrine safe from injection attacks in whatever it is doing now?
How is Doctrine safe from attacks, when it lumps statement and parameters into the same single query, per query? Does it really do something else here?
Doctrine uses PDO internally in most cases.
http://php.net/manual/en/pdo.prepare.php says in part:
PDO will emulate prepared statements/bound parameters for drivers that do not natively support them, and can also rewrite named or question mark style parameter markers to something more appropriate, if the driver supports one style but not the other.
When emulation of prepared statements is enabled, the prepare() that your app runs is basically a no-op. PDO saves your SQL string, but it does not send the SQL query to the database server at that time.
Then when you call execute(), it copies your parameter values into the appropriate places in the query, using proper string-escaping. Then it finally sends the final string to the database server. No prepare is done at the database server, it just executes the query as-is.
This is also how PDO supports both positional (?) and named (:param) parameters for all brands of RDBMS, even though most brands support one or the other style, but not both.
If you disble emulation of prepared statements, you should see both the Prepare and the Execute lines appear in the query log. I believe this can be done in Doctrine this way:
$pdo = $entityManager->getConnection()->getWrappedConnection();
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
While I don't know the Doctrine library specifically, I can speak to MySQL logs and what's going on as far as the DB is concerned:
The first example (prepare/execute) uses prepared statements, while the latter (query) does not. Prepared statements have a number of advantages, primarily performance- and security-related (avoiding SQL injection, as you mentioned), and I would personally avoid an ORM that did not use prepared statements, as they are generally considered a best practice for executing queries from within an application.
That's not to say that Doctrine isn't doing some sanitation internally to protect from SQL injection, and I certainly hope it is; at the same time, it would be more effective to use prepared statements, and I don't know why they wouldn't.
I'm working on an application at the moment that uses PDO with a MySQL database.
I'm seeing some queries, which are just very simple SELECT statements, e.g.
SELECT * FROM table ORDER BY name ASC
The code does not use prepare, for example:
$sql = "SELECT * FROM " . $this->table . " ORDER BY name ASC";
$stmt = $this->db->query($sql);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $results;
Is it ok to do this, i.e. without using prepare, if there's no placeholders in the query?
The reason I've asked this is because according to the documentation it says
The SQL statement can contain zero or more named (:name) or question mark (?) parameter markers
which makes me wonder why you'd use this in the case of having no (zero) parameter markers?
Yes, because the use of prepared statements have 2 main causes:
Enhance running the same query with different parameters.
Prevent sql injection by separating sql code from the parameters.
Since you have no parameters that could be handled by a prepared statement (table names cannot be a parameter), you do not gain anything by pushing the query through as a prepared statement.
You still need to make sure that whatever is returned by $this->table will not cause any issues with the generated sql code.
Of course you can omit prepare if there is no dynamic data in your query.
But prepared statements have more advantages than only securing your queries.
According to http://php.net/manual/en/pdo.prepared-statements.php a second advantage is, that statements can be prepared once and executed multiple times.
The query only needs to be parsed (or prepared) once, but can be executed multiple times with the same or different parameters. When the query is prepared, the database will analyze, compile and optimize its plan for executing the query. For complex queries this process can take up enough time that it will noticeably slow down an application if there is a need to repeat the same query many times with different parameters. By using a prepared statement the application avoids repeating the analyze/compile/optimize cycle. This means that prepared statements use fewer resources and thus run faster.
Nevertheless, if you run your query only once and there is no dynamic data inside your query, omitting prepare is also fine.
In reality, you have to run such a query extremely seldom. A few tables with configuration-like options may be.
In all other cases at least LIMIT clause is obligatory.
So the question is rather a theoretical one.
The PHP manual states the following:
Calling PDO::prepare() and PDOStatement::execute() for statements that
will be issued multiple times with different parameter values
optimizes the performance of your application by allowing the driver
to negotiate client and/or server side caching of the query plan and
meta information, and helps to prevent SQL injection attacks by
eliminating the need to manually quote the parameters.
PHP PDO::prepare
For a single, once a page query - say:
$query = "SELECT id, content FROM pages WHERE id = :id LIMIT 1";
Is using prepare and execute like:
$statement = $connection->prepare( $query );
$statement->execute( array( ":id" => 5 ) );
The best way to go? I get a feeling from the manual that I should only be using prepare() for queries that will be bound multiple times. If this is the case, what are the other options? (Manually calling quote, and then PDO::query() possibly?)
I can't say if there are any performance implications when using prepared statements for a single query only.
Every query is parsed, analyzed and optimized. That also applies to PDO:query() (and mysql_*, mysqli_*, …). Prepared Statements - simply put - separate parsing, analyzing, optimizing and query-planning from executing the query. My (possibly naiive) assumption is that the only overhead prepared statmenets pose for a single query is the caching of the prepared results.
Using one API for executing queries should outweigh slight performance penalties, though. If you were to use PDO::query() instead of PDO::prepare() for single queries, you'd miss out on on the parameter binding and automatic escaping prepare() offers out of the box. This - potentially - opens a new can of worms, should you forget to PDO::quote() your data.
I only use PDO::query() for things that cannot be prepared in a reasonable fashion (e.g. "static" queries like SELECT foo FROM bar ORDER BY bla DESC LIMIT 1 and queries heavily using IN() et all).
Is there any point in saving PDO prepared statements for reuse in a session?
I'm building a site that uses MySQL fulltext queries, which I'm putting together in my PHP, like
SELECT * FROM table
WHERE MATCH (title) AGAINST ($search_string IN BOOLEAN MODE) AND
MATCH (keywords) AGAINST ($keywords IN BOOLEAN MODE)
ORDER BY $order_by $asc_desc
It seems to take a lot longer to run this kind of query when I prepare and execute it with bound parameters, than when I just prepare and execute a query string with the values included. But I need to use prepared statements to prevent the risk of SQL injection.
In any session I would very likely run the same query several times, with different parameter values. Would it make sense for me to save the PDOStatement object once it's been created (for example in the session)? If so, what would be the best way to do that? Would it be good practice to save each prepared statement in an associative array as it's created, with the SQL query string as the key for each?
On further reading I found you can't use bound params for the ORDER BY and ASC / DESC part of a statement. When I replace these with fixed values the performance improves.
There is no benefits to store prepare statement into session for reusable purpose,
the expensive cost is on the query execution itself.
If the data you are grabbing constantly changes, then caching the resultset may no longer be valid shortly after you retrieve them.
However, if your data appears to be static:
session_start();
$_SESSION['cachedResultSet'] = $fetchedResultset;
echo $_SESSION['cachedResultSet'][0][0];
# above statement `echo ...` depends on how your result is, be it an array or object
I think it would be acceptable to a degree to store resultsets in session variables, but perhaps it would depend (sorry to be redundant) whether the data changes quickly or on how often you grab this particular resultset, etc...
Is there any way to execute more sql prepared statements at once? Or at least use something to achieve this result, can it be emulated with transactions?
pg_send_query can execute more statements (from php docs "The SQL statement or statements to be executed.")
but
pg_send_execute and pg_send_prepare can work only with one statement.
The query parameter has the following description
"The parameterized SQL statement. Must contain only a single statement. (multiple statements separated by semi-colons are not allowed.) If any parameters are used, they are referred to as $1, $2, etc."
from http://www.php.net/manual/en/function.pg-send-prepare.php
Is there any way to send more statements at once to make less roundtrips between php and postgresql like the pg_send_query does?
I don't want to use pg_send_query because without parameter binding I can have sql injection vulnerabilities in my code.
The round trips to the DB server shouldn't be your bottleneck as long as you are (a) using persistent connections (either directly or via a pool) and (b) aren't suffering from the "n+1 selects" problem.
New connections have an order of magnitude overhead which slows things down if done on every query. The n+1 problem results in generating far more trips than is really needed if the application retrieved (or acted upon) sets of related rows rather than doing all operations one at a time.
See: What is the n+1 selects problem?
Separate your queries by semicolon:
UPDATE customers SET last_name = 'foo' WHERE id = 1;UPDATE customers SET last_name = 'bar' WHERE id = 2;
Edit:
Okay you cannot do this on the call side:
The parameterized SQL statement. Must contain only a single statement. (multiple statements separated by semi-colons are not allowed.)
Another way would be to call a stored procedure with this method and this SP issues multiple statements.