Recycle relational and ADO.NET objects in query execution #24206
Labels
area-perf
closed-fixed
The issue has been fixed and is/will be included in the release indicated by the issue milestone.
type-enhancement
Milestone
While doing some memory profiling on Fortunes, a lot of objects are being allocated which seem like they should be recycled (numbers are for a run with 30k iterations):
Note especially all the Stopwatches getting allocated - 6th place global allocations. Also, the above screenshot is just a simple of the top objects, here are some more:
NpgsqlParameterCollection
,List<NpgsqlParameter>
,NpgsqlParameter[]
,RelationalDataReader
,NpgsqlStatement
,List<NpgsqlStatement>
.We have a small architectural blocker for recycling these... RelationalCommand gets generated as part of compilation, and cached globally in RelationalCommandCache. In effect, it's an immutable, shared type, which prevents it from caching resources such as Stopwatch, DbCommand, RelationalReader, etc. PR #24207 is a hacky prototype for caching a RelationalCommand on RelationalConnection, and populating it from the RelationalCommand stored in RelationalCommandCache; this allow caching most of the resources needed for executing a query. With this PR, instance allocations go down by 27%, byte allocations go down by 18%, and Fortunes RPS goes up by around 2.3%.
A better design would be to split RelationalCommand and have, e.g. RelationalCommandInfo, which is the cached result of compilation; it cannot be executed, is immutable and just holds the CommandText and Parameters. RelationalCommand would then be initialized from this and executed as above. This would be a provider-facing breaking change though.On a related note, we currently dispose ADO.NET objects (NpgsqlConnection, NpgsqlCommand) when a query is complete, when we could be reusing them. This PR also does that.
The text was updated successfully, but these errors were encountered: