zodb / relstorage

A backend for ZODB that stores pickles in a relational database.
Other
55 stars 46 forks source link

Performance regression with prefetch compared to 2.1.1 in rare cases #312

Closed jamadden closed 4 years ago

jamadden commented 5 years ago

In some zodbshootout scenarios, depending on the database connection and latency, 2.1.1, which doesn't implement prefetch, can actually outperform 3.0a, which does. In 2.1.1, we would have made sequential calls to get each cold object's state, whereas 3.0a makes one large query to get the state all at once. In 2.1.1, though, the sequential calls were a prepared statement (on PostgreSQL), whereas it's not currently prepared in 3.0a --- we can both prepare and use an array parameter (instead of the generic batcher) on Postgres, which will likely make up the difference.

I also think that the cache size plays a part here; it's quite likely the worst benchmarks were when the local cache was actually set to size 0, so we make the extra query for no benefit and then turned around and make the sequential calls. We should be more careful about that, both special casing size 0, and perhaps not requesting more data than will actually fit in the cache (?).

jamadden commented 4 years ago

In 08259fa9, the prefetching was changed to [short-circuit most of the work] (https://github.com/zodb/relstorage/commit/08259fa909b63f25e5b07b2f866c7d82104460a3#diff-5c2ca3e44f9343bf7373eb767c0f4379R479) if we know the results won't fit.

I've re-run benchmarks this morning on that case and find no substantial difference from 2.1.1 to 3.3.

I'm not sure what a more sophisticated policy would look like. "[P]erhaps not requesting more data than will actually fit in the cache" requires either (a) a complex (windowed?) SQL query to limit the size returned or (b) throwing away data in Python once its gone across the network. Neither is appealing. There's also the issue of fairness across users of the cache, since one prefetcher could dominate the cache and eject other things needed by other connections sharing the same cache.

Unless someone can come up with a better heuristic, I think the best thing to do now is probably to punt and suggest that it's a problem for the deployer and application developer to correctly size the cache and take advantage of prefetch in a way that best suites the application.