single connection concurrent transaction #282
Replies: 6 comments
-
Hi Tobias. This is already implemented in Postgres.js and is called Pipelining, so yes - definitely possible 😉 Now when using Postgres.js you need to use To achieve pipelining with transactions you simply return an array with the "unawaited" queries like this: const result = await sql.begin(sql => [
sql`select 1 as a`,
sql`select 2 as a`,
sql`select 3 as a`,
sql`select 4 as a`,
sql`select 5 as a`,
sql`select 6 as a`
]) In v1 there is no limit to the number of pipelined queries per connection, but through testing I've found pipelining benefits max out around about 100 pipelined queries (of course different depending on the connection), but since a broken connection will throw all those queries I think it's a good tradeoff to set a boundary on the amount of queries pipelined, so in v3 - 100 is the default, but can be configured using |
Beta Was this translation helpful? Give feedback.
-
hmm, the pipeling does for queries within this transaction what independent queries can do without pipeline. But there might be some more optimizations potential. please give me some time and keep this issue open. I want to do some test and study the code. |
Beta Was this translation helpful? Give feedback.
-
No problem :) A possible optimization in v3 is allowing multiple full transactions to be pipelined, but to be honest a lot of real world scenarios can do that be using CTE's instead which in any case I can think of is a better way of going about it anyway. Also, I read your comment to the article linked, and I think it's telling of a footgun in Postgres.js that you tried to run transactions like you did. I would love your insight to improve either the documentation, or if there should be a mechanism built in to prevent users of the library to try and do transactions like that which could be very dangerous? |
Beta Was this translation helpful? Give feedback.
-
So,... this is the second time I start writing: I often see the pattern of processes that can be triggered from API or message-system, that looks like this: async function(args){
await sql.begin(t => {
const items = await sql`select * from items where id in (${args})`;
const relatedItems = await sql`select * from items where id in (${items.map(i=>i.relatedId)})`;
// some processing, sorting, mapping filtering ....
await sql`update ...`;
await sql`update ...`;
});
} Here is a timeline for this process. We have only one connection and it is called twice.
All we talk about is how to remove as many numbers as possible (remove as much waiting time as possible.)
Because of this, that we do not want to pipeline queries that are supposed to run in a transaction, to run without transaction, we have to await the If the postgres server allow us to send a flag with each query of (execute only in transaction), then it would be possible.
pipelining as of todayThe pipelining with 5 queries causes the following timeline today:
We have to await the number 1, I think there is potential to avoid number 4 and 5 awaiting. for number for awaiting, I made a change rewrite...TobiasNickel:rewrite This change is immediately pipelining the commit command. This is ok, because the db will automatically turn this into a rollback if needed. The application is going to receive the first error from conclusionI have not been able to bring a revolution with But I hope this post is valuable for you. |
Beta Was this translation helpful? Give feedback.
-
Postgres protocol, supports |
Beta Was this translation helpful? Give feedback.
-
Interesting topic. I've also just recently suggested to implement a |
Beta Was this translation helpful? Give feedback.
-
hi, yesterday I read this article about concurrent transactions (mysql) dev.to.
And I found in order to make the transaction concurrent, there was a very large connection pool (38). and on a single connection there is always only one transaction AND only one query at a time (that is how the mysql driver works).
This postgres module is able to run many queries concurrent on a single connection, by instantly sending them, without waiting for previous responses. Because postgresQL respond results in the same order the queries where send, the results or errors can be mapped back to the original query/promise.
What I liked in the article was the syntax, of fire of many queries, but not await them, and only await the final transaction to finish.
In a very limited test, I was able to show, that in postgres(with the DB server) we could even send many transactions concurrently on to the db on a single connection. If this module can support a syntax/pattern, it would be possible to gain huge performance boosts.
here is my test script:
AND here is the result (with a remote slow database):
I am thinking about a syntax like this:
This can work with postgres, because we can send 10 update queries as part of a transaction. when the third update query fail, postgres will give us a distinct error for every of the following other update queries AND turn the final commit command into a rollback.
I know in real code, the potential gain is unlikely 10x like in the little example, but 30-50% should can be realistic.
What do you think? Do you think it is possible to support "Concurrent transactions on single connection" within this project? any other thoughts?
Beta Was this translation helpful? Give feedback.
All reactions