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
perf: Optimise the readonly (true / false) call #1228
Comments
@benbenw , could you please create a JMH benchmark to highlight the issue and/or quantify the changes? The benchmarks are located here: https://github.com/pgjdbc/benchmarks |
No ! 😟 Moreover before coding anything, we should choose a solution, I've highlighted 2 possibilities but you may have other and hopefully better ideas. |
That is great
I agree, however "before coding anything" we should agree if the bug is in the driver or if the bug is in the application itself. Sample code helps with that. We would need to quantify the change anyway, so a benchmark would be required here to merge the change to ensure we get improvement and we prevent a regression. PS. On top of that it might make sense to pipeline "setReadOnly" calls with subsequent queries, so |
There is no bug in the driver. It's a perf improvement. Here the driver could be better out-of-the-box, that's why I opened this issue. |
The reason we are asking for a benchmark isn't to dispute your findings it's to ensure that we don't introduce regressions later on. |
I agree with this approach it seems minimally invasive |
The sad thing is:
It does sound cool, yet it is something to be developed. |
@davecramer are you working on this? I was starting to take a look, but do not want to duplicate effort.
Does autocommit really matter? On brief look it appears that even if autocommit is true the result would be:
That seems like it should be fine, right? |
The thing is in autoCommit=true, the driver issues NO Using explicit
|
@bokken no, I'm not working on this, so go ahead. as for "that seems like it should be fine" I don't agree. By wrapping a read only connection in a transaction we are changing the transaction isolation. After the BEGIN all subsequent selects are executed within this transaction, and will be subject to the transaction isolation semantics. While this may seem innocuous it is certainly an unintended consequence of setReadOnly. Given that setReadOnly is meant to be a hint to the driver I'm not comfortable with this approach. To complicate matters further it is actually possible to write to temporary tables in this mode. I'd be more interested in an optimization that somehow (I have no idea at the moment) found a read only connection from the possible connections and used that. |
Then valid "improvement" would be just rip off |
You are correct. The key piece is in PgStatement (and likely other places) where if autoCommit is true, the flag QUERY_SUPPRESS_BEGIN is passed in. |
I suggest the following:
Any thoughts? |
+1
We already have that.
Looks like this might be pretty simple. Working on a prototype now.
Just to clarify, the goal is to handle when both read only and auto commit are true? |
Given that this does not actually provide any performance benefit unless we can route queries to a read only host I would suggest the best optimization is to make it a no-op. |
The case there is as follows: the app knows it is about to execute a readonly query and it wants to hint the downstream on that, so the downstream uses REPLICA instead of master DB. AFAIK the only way for pgbouncer can tell readonly from a readwrite query is via However, that ("force begin readonly") might come as a separate improvement. |
There's a relevant StackOverflow question on quorum based synchronous replication, targetServerType, and picking the best server |
Interesting. Figuring out which server has the lowest lag would introduce quite a big of overhead in picking the connection. Back to pgbouncer. It seems currently the only legitimate use case is to give a hint to pgbouncer. As this is only useful if the autocommit=false this is quite limiting. In which case I'd be in favour of the non-default setting to force begin readonly. Ideally I'd like to make this more generic for all of the other pools but that's not our problem at the moment |
I agree with all of that. The discussions over on #848 all still show a transaction being used (i.e. autocommit set to false). |
If autocommit is set to false, read only will be set on begin transaction. If autocommit is true, it will continue to be managed at session level. The queries to change session have been cached to avoid re-parsing each time readonly value changes. pgjdbc#1228 pgjdbc#848
* feat: read only transactions If autocommit is set to false, read only will be set on begin transaction. If autocommit is true, it will continue to be managed at session level. The queries to change session have been cached to avoid re-parsing each time readonly value changes. #1228 #848 * feat: read only transactions * checkstyle and hamcrest test import * add connection property with 3 options to control read only behavior * fix missing property methods on BaseDataSource * avoid redundant static modifier * more loosely couple read only hints to backend * return default read only mode from data source. * avoid case conversion
read only transactions help when Serializable isolation level is used. Quoting docs:
|
@redbaron So the very first thing we asked the original reporter for was a benchmark in order to measure the possible performance benefit. It would help us immensely if we had such a benchmark to actually test and prove that any changes we made actually made a difference. Care to put one together ? |
It's quite common to see applications doing :
Surprisingly the setReadonly call is costly (memory allocations / cpu) (from the driver perspective not the db)
You can mitigate this by activating
preferQueryMode=extendedCacheEverything
but it comes with its own problems :This comes from real world performance analysis.
For each call, the driver is calling
pgjdbc/pgjdbc/src/main/java/org/postgresql/core/Parser.java
Line 1057 in b7fd9f3
pgjdbc/pgjdbc/src/main/java/org/postgresql/core/Parser.java
Line 44 in b7fd9f3
I think there is room for improvement.
I see at least 2 solutions :
pgjdbc/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java
Lines 287 to 291 in b7fd9f3
The maintainers will probably have more ideas.
This analysis may apply to the other "internal queries" of the driver but we mostly have troubles with the "readonly" ones.
The text was updated successfully, but these errors were encountered: