-
Notifications
You must be signed in to change notification settings - Fork 845
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
Postgres hanging on large DDL commands #431
Comments
Can you please provide a test case that exhibits your problem? |
I've put the link in the PR back up again. And there is a simple code snippet which reproduces the issue. Or do you want a PR with specific test? I wanted to discuss that before submitting tests, but I can submit the test if that's what you need. |
Exactly. |
I've pushed the test to: #432 |
The smaller the code base, the smaller number of bugs we have. |
@zapov , you mean that when running simple query, postgresql supports semicolon-separated compound queries and never hangs, don't you? Does it require a specific backend version? |
Yes, that is correct. No, it should work on all versions. |
Are you sure lots of |
Then something like #365 might be worth including, however I do not like the way you hijack Can you please retry #365 without adding |
Yes. I opened this issue for discussion if it's a good idea to use simple protocol for non prepared queries and extended protocol for prepared queries. My previous PR was as such so I don't introduce any changes to the JDBC, but that's why it was a bit hacky. Can redo it if we are settled on the proposed behavior |
Does it hang?
I see two aspects:
It seems "simple protocol" somehow solves "hanging on large SQLs" issue. There might be similar issue with
So, it makes sense to benchmark the impact of using simple protocol for non-prepared statements. |
So I took a look at this more closely over the weekend... and came to the conclusion that as things are currently implemented, it doesn't seem worth changing non-prepared statements to simple protocol ;( Not sure where to go from here...
which I guess is kind-of ok since v2 is probably going to be deprecated. I actually implemented change in the driver... and almost all of the test pass - only few issues with BEGIN/transactions behavior which I didn't look too closely ATM. So now I'm thinking about using public API outside of javax interfaces to get such a behavior, but it seems that it all ends up in the same place... so not too much different than my implementation of simple protocol for non-prepared statements. Regarding benches... I actually maintain one DB driver bench where JDBC is tested explicitly and implicitly (and I've noticed few performance regressions on some places in last few versions). I'll probably take a look at v2 again next. btw. I think it would be better to refactor the code in such a way that I can introduce such change without modifications of the current codebase - but that's unrelated discussion. |
what is the showstopper there? |
There is no real showstopper ... as in it can be refactored... just it looks too costly and risky. I still think thats the best design (simple protocol for non-prepared queries, extended for prepared), but I couldn't change the current codebase cleanly. So I'll look into what can be done with hanging (either by calculating the whole query size before.... or something else). I tried to reproduce the bug with smaller test (which builds up the large query) but couldn't. Issues I had while refactoring:
probably some others I can't remember just now. |
So I found some time to finish up this CR. It can be seen in PR: #450 I maintain DB driver bench at: https://github.com/ngs-doo/dal-benchmark
While the numbers are not stable, on average they show if there are some regressions. Only noticeable regression is for Revenj find_many/find_one which uses simple protocol. It seems it became a lot slower on binary protocol, but it's fast again when simple queries is enabled. All JDBC queries are using prepared statements. |
@zapov , did you investigate why is the regression? |
I looked into it now. The bench is used for comparison with .NET so I need to gather formatted output somehow, so it's not an ideal candidate for JMH. Thinking about it some more, even if we enable simple queries by default (in my patch) it will still be much slower due to PT=-1 argument. It seems to my that SQ should take precedence over PT=-1 for non-prepared statements. |
@zapov , it would be nice to have less tunable parameters as no one knows what values to set. If "text query always improved performance", it would make sense to enable the feature by default. Am I right your main concern is "thread stuck due to non-consumed input"? |
I agree that there should be less parameters which goes in hand if non-prepared statements use simple queries. I'm fine with refactoring into that if we agree on that behavior. Also I think PT=-1 should not force non-prepared statements into prepared statements. Not sure if forceBinary should do that, but explicit forceBinary is much better than PT=-1. I don't think PT parameter should have any influence on non-prepared statements. If you look into the numbers, it's interesting to notice the difference between search_all numbers. I think prepared statements/non-prepared statements map naturally to Postgres v3 protocol extended/simple queries. And plus it will solves my main problem of having large sql query hang. Not sure I'm understanding you fully, but yeah, Java thread get's stuck on sending data over the wire. Even if I start another thread to look onto the one executing the commands, it doesn't really solve my problem. The only thing I can do is kill that thread - which means I still can't apply that SQL to the server. And the simple solution to that problem is using simple queries which include length as part of the command, so Postgres copes with it. |
binary != prepared.
Can you point to the code what is "prepared statements with text protocol"? |
I believe the thread gets stuck just because there is no thread that performs reads while the thread does its writes of the large query. Here's description:
Here's a workaround for batch executions:
I wonder what if we add dedicated thread pool to perform reads, so no deadlock happens. |
Did you mean "using text queries on non-prepared statements mostly improves performance"? |
When I say simple queries I'm referencing Postgres terminology. On v3 Postgres supports simple and extended queries. I'm referring to this:
PT=-1 caused forceBinary to be enabled. Postgres supports both binary and text protocol. Ah I see now what you mean (reading using another thread). Did not try that. |
I wish I never saw that. That looks strange indeed. |
So I looked at this today again... and managed to get it working... although it required a separate thread for flushing the output stream and buffering the entire stream in memory before sending. Also, I noticed strange behavior in this construct:
since if I understand that correctly, that will actually commit transaction if queries are run in autocommit mode. Right now the easiest solution for my problem is to get an instance of PGStream, but it doesn't seem available anywhere. |
Can you share the code? I thought offloading "read path" to a separate thread should be the easiest approach.
Do you mean |
Sorry, don't have it around anymore. Only committed the final version ;( Yeah, thats what I mean. I wanted an escape hatch so I can handle it myself without introducing additional complexity into the driver. |
If that works from functional point of view, we can then refactor it if required. |
Yeah, it worked. If you are interested how that looked: ngs-doo/dsl-compiler-client@9195a04 Btw. it would be nice if there was a way to get connection without a cast, but not really a big issue. |
Ah, you mean "get PGStream to the application so it could execute simple query"? Then it sounds very bad. It thought you need PGStream for multithreaded code to work. |
Ok. Tnx for your help. I guess I'll find some other workaround |
I guess as @davecramer returns back, something like #450 can be merged. |
I created a PR while ago: #365 because I had a problem with executing SQL scripts via JDBC. Recently Postgres started hanging while executing those scripts.
This happens on Windows/Linux and is reproducible with those scripts. I experimented with changing buffer sizes (send/receive) but it's not really a solution (while some scripts pass, other fails).
Looking at the JDBC code it looks like it splits those large sql statements into smaller parts and tries to send them using extended protocol. It looks like Postgres doesn't cope well with that... so first obvious solution looked like just send it using simple protocol (which includes sql length - so there would be no issues).
I still think that's far better solution than to rewrite that query into smaller parts.
Is there any reason I'm missing why we don't use simple protocol for non prepared statements. Most queries are executed with prepared statements (to pass in the parameters)... so I can't think of a good reason not to use simple v3 protocol in that case.
Executing those scripts using v2 protocol hangs also.
Regards,
Rikard
The text was updated successfully, but these errors were encountered: