-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Optimize dispatch_param_event allowing to skip unused pdo_param_event(s) #6047
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lgtm
Hi! I'm the one that reported this problem on php.internals mailing list so here's my repeated benchmark results. Before (master branch)prep: 0.019, exec: 0.175, fetch: 1.980 After (this pull request)prep: 0.006, exec: 0.145, fetch: 0.006 So it's a lot faster, this indeed fixes the problem. The prep and exec differences are just disk cache, but I confirmed where this problem is already, fetch is now fine and doesn't iterate doing nothing a few million times. Here's a gist with the script i used to benchmark this while looking for the problem and schema: BUT there is a reason I didn't make this pull request myself, please be careful around here: php-src/ext/pdo_pgsql/pgsql_statement.c Line 402 in 1297cf7
Wouldn't this break the case of using PARAM_INPUT_OUTPUT bind params? They seem to be used for INOUT parameters in stored procedures. This is my first time digging around the PHP codebase, but it does seem like this path could still be called in case of PDO_PARAM_EVT_FETCH_PRE and PDO_PARAM_EVT_FETCH_POST. |
Thanks @inoric, that's great news! Nope, as you can see in php-src/ext/pdo_pgsql/pgsql_statement.c Line 300 in 1297cf7
|
I saw that, it's the reason I thought it was safe to remove, but that break/return is only called if stmt->supports_placeholders == PDO_PLACEHOLDER_NAMED is true (the part I linked is in the else statement). I have apsolutely no idea when that will be false, but just wanted to leave a warning if someone missed that part. |
I found where it's set. php-src/ext/pdo_pgsql/pgsql_driver.c Line 261 in 1297cf7
Maybe make |
@inoric that part is a bit dodgy tbh. It's been a long time since I worked with the innards of pdo_pgsql, but I can't recall why that bit of code would have to ignore the event type. Also the pdo_sqlite/mysql/pgsql tests pass with the PR as-is, which is even more worrying ;-) |
@mbeccati Well, one likely reason they all pass is because not a single test uses PDO::PARAM_INPUT_OUTPUT, at least according to my very sophisticated |
@inoric A bit in a hurry, but to me |
@mbeccati Woops. You're right. Read that wrong initially and it was stuck that way in my head. Should be safe then? We should never modify parameters while fetching rows unless it's an INOUT, which is not done here anyway. Alternatively if we're gonna be paranoid maybe use my earlier suggestion to move the skip flag from connection to statement level and skip the optimisation if someone for whatever reason uses emulated prepares in postgres. |
@inoric most likely there's actually room for more optimizations here. With EMULATE_PREPARES turned on, the bool -> 't'/'f' conversion is probably being made on all the events rather than just the one that actually needs it. |
I wanted to say that I can't imagine someone using emulated prepares in postgres today, but then I saw this: php-src/ext/pdo_pgsql/pgsql_driver.c Lines 239 to 244 in 1297cf7
Emulated prepares seem to be automatically enabled when a scrollable cursor is used (not sure why). And scrollable cursors would be hit even worse by this problem since they could fetch each row more than once. Btw. I had another, more flexible idea of solving this, but it's more complex, and would be a bigger change to interfaces so it didn't seem like a good candidate: |
@inoric It's been 10+ years, so I can't recall why I had to use emulation to fix cursors. Does anyone really use PDO cursors anyway? The last commit should optimize emulated prepares a little further though and hopefully remove any doubts you might have. I don't think it's worth adding new hooks at this point. |
@mbeccati As I said, didn't mention it before because it seemed too complex. |
@inoric It would be great if you could create an entry on bugs.php.net, so that it can be referenced in the NEWS files and final commits. I will ask on internals and see if I get permission to push the fix from 7.3.x upwards. |
The reason are proxies like https://www.pgbouncer.org/ The can operate in different models (session, transaction, statement). One "problem" with prepared statements is that they create "state" on the server which is not compatible with such proxies operating in modes like When you activate emulation, you "solve" this problem. Also, for some using prepared statements is a overhead (i.e. additional round trips to the server to manage states) they won't to avoid. Surely depends on the traffic to measure this. |
@mfn Thanks for the explanation. I actually planned on using pgbouncer in one setup soon, but didn't look at the details yet. |
However OT, let me emphasize: |
* pdo_dblib doesn't use param_hook * pdo_firebird is messy and seems to even use the NORMALIZE constant in a wrong context
Manually merged in 44ade0e |
For review only, please don't merge.
First try to optimize unneeded param_hook calls by using . A few open items: