-
Notifications
You must be signed in to change notification settings - Fork 854
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
Potential performance issue with LoadTypes #2183
Comments
The performance gain by using @nicois, who originally contributed this feature, may have additional thoughts on this. |
@jackc Thanks for the insight. My testing was on local machine with db running locally, so it's possible the comparisons would be closer if testing against remote db. I also added some logging around our wiring up of the db connection, and found that we are repeatedly registering types. I'm wondering if there isn't a better way to wire this up or something. What we're doing now is using //stdlib here is pgx/stdlib
sqldb := stdlib.OpenDB(*pgxCfg, stdlib.OptionAfterConnect(func(_ context.Context, c *pgx.Conn) error {
return PgxRegisterCustomPgTypes(c)
})) then inside of that register func, I'm checking to see if the connection's type map already has the first custom type registered or not and logging it out: cTyps := []string{"custom-type-1", "custom-type-2"}
typMap := c.TypeMap()
_, customTypeExists := typMap.TypeForName(cTyps[0])
logger.Info("PgxRegisterCustomPgTypes called", log15.Ctx{
"customTypeExists": customTypeExists,
}) I'm seeing this log entry getting called a lot, and Alternatively, if caching custom type registrations to use across connection pool connections isn't something built into pgx, would there be any reason I shouldn't cache the Thanks again 😄 |
Each connection has its own type map, so this will get called every time a new connection is created.
It is not built in.
This is not safe for some types because not all Codecs are concurrency safe. In particular, Anyway, it's an open question if or what to do about reusing |
Thank you for taking the time to go into the weeds a bit to explain to this level of detail - very much appreciated! I did a proof of concept to cache the As for speed, doing them 1x1 with If, however, you're open to the idea of caching these... Some of the types in pgx have a I'd be happy to put up a PR if that seems reasonable. All in all, pgx is a really well done body of work! It's a bit lower-level than I normally work at and I've learned a decent bit reading through it 😄 Thanks again! |
This approach would work in the overwhelming majority of cases, but there is the potential for some nasty edge cases.
We have no guarantee that caching is safe. |
Oh wow - I didn't realize that OIDs could be different across a replication set 🤯 |
Describe the bug
Recently updated from
v5.5.5
tov5.7.1
and used theLoadTypes
func to load up custom types en masse instead of 1-by-1. We hit some hiccups in that our cluster of 5 servers would spawn up and then our postgres server would crash. Upon troubleshooting the logs showed a pretty massive recursive CTE which led us to the buildLoadDerivedTypesSQL func. We rolled back our release (which had more than just pgx upgrade) and it became stable again. To be clear, I'm not saying this caused the crash - haven't replicated it on any other dev/test environment to figure out for sure. Just wanted to share these findings below.We have 53 custom types that we load up in an after connect hook with the driver. I then cloned the pgx repo and made use of the test setup to benchmark both ways. I'm not expert at benchmarking, but if this is relatively correct there's a fairly major penalty for using
LoadTypes
as opposed to iterating the custom types and one-by-one usingLoadType
. My findings are roughly 20x slower to use the recursive CTE pathway.To Reproduce
I added tests like this to the
derived_types_test.go
file against custom types I already have defined in my db.Then I execute the benchmark tests for 30 seconds and get the result:
Expected behavior
Bulk loading, especially via such a massive recursive CTE, would ideally provide some benefit. Otherwise, the bulk operation could just iterate over the slice of strings and do
LoadType
for you and register it.Actual behavior
Seems to be significantly less performant, and potentially risky combination of recursive CTE and dynamic sql 😅
Version
go version go1.22.9 darwin/arm64
PostgreSQL 15.5 (Debian 15.5-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
v5.7.1
The text was updated successfully, but these errors were encountered: