views:

343

answers:

5

I understand the security benefits of prepared statements in MySQL. No need to cover that topic here. I'm wondering about the performance aspect of them.

Now, I know when a query using a prepared statement is executed twice in a single PHP script, it's faster because the query is only parsed once, once for each query. The client makes one trip to prepare, then sends data twice using the binary protocol. The binary protocol is faster, and you're not taking the hit of having to parse a second time.

However, what about the case where I only want to perform a query once in a single PHP script? It would seem using a prepared statement is worse, because you're making two trips to the server, once to prepare, and once to send the data. The benefit of only having to parse once is lost, and you're penalized for that second trip. If the data isn't sufficiently smaller in binary format, you lose by using a prepared statement, right?

However, I've read some conflicting reports about what PHP's mysqli or PDO libraries do? Do either of them cache the prepared statement across script execution? Is the server going to have to parse the prepared statement again on a subsequent pageload or not? If the answer is no, that the statement doesn't have to be parsed on the second pageload, then it would seem that prepared statements ARE better, even if you're only executing the query once per pageload.

Please take into consideration if anything has changed between versions of MySQL regarding this. You can safely assume I'm using PHP 5.2

EDIT: Just to make it clear, I want an answer for MySQL and PHP specifically, specifying the MySQL version and if this was ever different, and to ONLY consider performance, not ease of use or security.

UPDATE: I accepted the answer I did because of the follow up comment had a few good ideas. I'm still a bit disappointed that no one seems to be able to answer the crux of the actual question I asked with any certainty. I guess sometimes the answer really is "it depends."

A: 

Using prepared statements is never really a bad idea. I've not used them recently with mySQL, but I've used them heavily with SQLSERVER - and they work great.

The PDO library probably doesn't do any caching but the database will for the prepared statement.

Plus as you covered they are great for security. Its also really nice to push that logic out of the code - you wont up with SQL sprinkled throughout your application.

Mr-sk
So MySQL will not have to parse the query on the second pageload? Are you sure? Do you have any documentation? And what version of MySQL are we talking about here? Or is this only for SQLSERVER?
Mike Sherov
A: 

What exactly do you mean "parsed on the second pageload"?

Each PHP process/thread/visitor that executes that same script again will NOT prevent MySQL from re-parsing the query to prepare the statement, as its valid in a per connection basis, so its very effective for queries repeated in the same script.

Now, I cant argue about prepare + execute vs simple query, performance wise (w/o repeated queries);

But, to save mysql from parsing a complex query in every single script execution, you should use stored procedures; a query would be just CALL items(date,search_etc,id); instead of SELECT i.id FROM products as p JOIN item_prodct as t ON... JOIN items as i... ON... WHERE ... p.date ... i.search_etc ...

You can use stored procedures with prepared statements.

Luxvero
What about when you are using persistent connections or pdo connection polling?
Mike Sherov
and what I meant by parsed on the second pageload is that some have implied that using persistent connections or pooling will allow the connection to be kept open and therefore a statement previously prepared will be again available. I know, it sounding like nonsense to me too, but that's why I asked the question. You can see that the other answerer to this question seems to think otherwise.
Mike Sherov
well, using ur application functions for prep_stmt Maybe, in PHP MySQLi for instance, how would you carry the stmt_init() object around ? Im not shure.. Dont know much about PDO sorry __but__ there is SQL syntax for prepared statetements, you can use even through command line, you basically assign a name to the stmt, and reference it later by that name, the parameters are session variables so __YES__ using persistent connections you could achieve that, it would be almost like a stored procedure, but with ability to return multiple rows
Luxvero
you would hardcode a variable name and stmt name, and if the variable iscreated<>yes you then prepare the stmt.. this is for whenever the persistent connection is droped.... .........and another BUT is that each script or thread should use unique variable names, so that thread dont mess with each other data,
Luxvero
Thanks for the attempts, are you now saying there is a way to not have to reparse the prepared statement on the second page load?
Mike Sherov
Yes, since statements belong the the session/connection Check it out http://dev.mysql.com/doc/refman/5.1/en/sql-syntax-prepared-statements.html ---- you save the mysql optimizer a lot of work, but i think u lose all the other advantages of prepstmt, but still seems a nice way to go
Luxvero
+2  A: 

The truth of the matter is that sometimes mysqli is faster and at other times mysql api is faster. But the difference is really really small. If you look at any of the performance tests on the web the difference is really just 10 - 20 milliseconds. The best way to boost performance is to optimize table design.

Many of the tests that 'prove' the older api to be faster conveniently forget that for maximum security mysql_real_escape_string() should be called for each variable used in the query.

Queries are cached by the server, if and only if the data on all the tables that are used in the query have remained unchanged.

e4c5
Yeah. I've already got a strong hand on table optimization. I'm not really asking about the query cache either. I'm asking about caching of a prepared statement to avoid having to reparse it in between page loads. Also, a lot of my queries are just inserting integers, so I do have the situation where I can just run intval on the input instead of mysql_real_escape_string. Also, 10 milliseconds do matter to me as I feel I've optimized whatever else I can.
Mike Sherov
The same prepared statment will not be used in between page loads. It has to be prepared every time.If squeezing every large millisecond matters, a store procedure might be a good idea (assuming you have a complicated query)A bigger boost can probably be gained by dumping your data into a text file and loading it with LOAD DATA IN FILE . It's a lot faster than a series of inserts.
e4c5
+4  A: 

The time you may save with one way vs another: 10 milli seconds

The time you save not having to explain to your client why all his user information ended up on 4chan: Priceless

Use prepared statements.

Cortopasta
This is NOT an answer. I explicitly in ALL CAPS said based on performance, and not security. I know how to protect input with either prepared statements or proper escaping, so I'm not interested in the security aspect.
Mike Sherov
I agree with Cortopasta. Performace ALWAYS takes a backseat to security. Ergo, the question is meaningless when debated outside of that context. And yes, I subscribe to the belief that if you are the programmer whose client's information was pwnd because you skipped security, then you belong in jail.
Chris Lively
I agree as well with regards to security trumping performance. However, as I stated several times, I already have a handle on the security of my data and the code that deals with my database. I am equally secure using either prepared statements or not considering this. Therefore, my question is about the nature of how prepared statements work between page loads and the performance characteristics of it vs. not using prepared statements. Whether or not you agree, I feel that's worth discussing when you're trying to squeeze every last millisecond of performance out of your database.
Mike Sherov
first google hit indicates prepared statements are faster. Just out of curiosity though, what kind of app are you building that requires shaving milliseconds from server-side run time?
Cortopasta
I have some pieces of code that are being hit 5 million times a day, responsible for over 2 billion sharded DB records of relationships between +10 million users. Milliseconds are very important to me :-) I'm pretty lucky to have the ability to see the performance benefits of such small changes, and so I like to explore every avenue.
Mike Sherov
A: 

re: "Using prepared statements is never really a bad idea" Not true. You can easily fill up the prepared statement cache and exceed max_prepared_stmt_count if you don't know what you're doing, rendering your app useless until connections consuming the prepared statements are closed. Prepared statements are specifically designed for tight inner loops in your business logic where you're going to be calling the same basic query over and over again, a good example being a parameterized query such as 'select name, address, phone from tbl where id = ?' and you have a different id on each call. That way, it's worth the extra round trip to the db for the prepare because you're probably going to call it hundreds or thousands of times and just change the parameter. But you're expected to remove the prepared statement from the cache or close the connection at the end of, say, your stateless script (php, perl, jsp, ruby, etc). If you don't remove the prepared statement and you are using a connection pool, you are bound to fill up the cache over time and get a nasty error "Can't create more than max_prepared_stmt_count statements". I'm speaking from experience so think about whether you really need prepared statements because you know definitively that you're going to be repeating the same parameterized query over and over in a tight loop. If not, what you're probably looking for is letting mysql use its basic query cache which is a different mechanism than the prepared statement list and which behaves like a true LRU cache from my understanding.

NormK