Skip to content
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

database/sql: statements created with conn.PrepareContext are re-prepared in transactions #28130

Closed
RaduBerinde opened this issue Oct 10, 2018 · 3 comments
Assignees
Milestone

Comments

@RaduBerinde
Copy link
Contributor

@RaduBerinde RaduBerinde commented Oct 10, 2018

I am trying to write a sql client that prepares some statements and then uses them in transactions. I am observing that Tx.StmtContext re-prepares each statement every time (defeating the purpose of using prepared statements, at least from a performance standpoint).

This is another incarnation of #15606. The fix for that issue addresses the case where we create the statement via DB.PrepareContext. However, I am using Conn.PrepareContext. I am then running transactions on the same Conn, which triggers the code path below because stmt.cg is not nil:

// [sql.go:2105, go 1.11]
	if stmt.closed || stmt.cg != nil {
		// If the statement has been closed or already belongs to a
		// transaction, we can't reuse it in this connection.
		// Since tx.StmtContext should never need to be called with a
		// Stmt already belonging to tx, we ignore this edge case and
		// re-prepare the statement in this case. No need to add
		// code-complexity for this.

Note that (as an alternative) using Db.PrepareContext once for the application is problematic for other reasons - we have multiple parallel workers and they contend on some internal mutexes in Rows objects. Perhaps I should use Db.PrepareContext once per each worker, even though I already have a specific Conn for each one?

I am using go 1.11.

CC @adams-sarah @kardianos @johto

@kardianos kardianos self-assigned this Oct 12, 2018
@bcmills
Copy link
Member

@bcmills bcmills commented Oct 23, 2018

@bcmills bcmills added this to the Go1.12 milestone Oct 23, 2018
@bradfitz bradfitz changed the title database/sql: statments created with conn.PrepareContext are re-prepared in transactions database/sql: statements created with conn.PrepareContext are re-prepared in transactions Oct 23, 2018
@kardianos
Copy link
Contributor

@kardianos kardianos commented Oct 27, 2018

@RaduBerinde If you start a Tx from a Conn, what you have are two views into the same database session. If you prepare a stmt on Conn, begin a tran, then execute the stmt on the conn, it will execute within the transaction (because the session is still open). We still prevent executing multiple commands at the same time from conn or tx because we wrap the driver conn in a mutex.

The short story, just don't use "StmtContext" and it should just work today.

I attempted to see if I could get this workflow working as you described, but the implicit stmt pool code is too complicated for me without spending many hours re-reading it. I was unable to find a simple fix that would work. So in this case, just don't use "StmtContext" on Tx, and just remember that you are operating on a database session, regardless of the objects you use on client space.

@kardianos kardianos closed this Oct 27, 2018
@RaduBerinde
Copy link
Contributor Author

@RaduBerinde RaduBerinde commented Oct 28, 2018

Thanks for the workaround. This limitation and workaround should be documented if it won't be fixed though.

@golang golang locked and limited conversation to collaborators Oct 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.