SqlClient optimize SqlDataReader and TdsStateParser snapshots - #37241
SqlClient optimize SqlDataReader and TdsStateParser snapshots#37241Wraith2 wants to merge 1 commit into
Conversation
|
@tarikulsabbir same here ... |
|
Thanks @Wraith2 🎉 We will be looking in to these PRs in near future. Working on internal deadlines which will take us some time to review these PRs. |
|
@Wraith2 This PR is being tracked and will be picked up for dotnet/SqlClient. Appreciate your patience for some more time while we come back to review and merge your contributions! 🙏 |
|
How is that going to be done exactly? |
|
Our primary focus right now is publishing GA Release v1.0 for Microsoft.Data.SqlClient in August, for which we are not taking further pulls unless they are necessarily needed. Our next preview release will be a near snapshot of what's coming in GA, for which we are wrapping up activities currently. Post GA 1.0 we will be open sourcing driver on dotnet/SqlClient and will then come back to review, port, test and merge all the remaining PRs in Microsoft.Data.SqlClient while also considering them to merge in System.Data.SqlClient (if needed). That's when we're aiming to speed up development and delivery and address PRs more actively! :) |
|
Based on that plan I've closed all PR's relating to performance improvements for SqlClient and when the code for M.D.SqlClient is available I can rework them onto that codebase. I've left open my bug fix PR's because those are small and applicable to both versions. |
Profiling the DataAccessPerformance project which emulates the TechEmpower fortunes benchmark shows that a lot the work done by SqlClient is spent in managing state snapshots. The data returned to the user is all string instances which are placed in a Fortune object but these aren't the dominators in the memory profile.
This PR changes the implementation of the snapshot mechanisms used by
SqlDataReaderandTdsStateParserObjectto:Keep track of a cached
SqlDataReadersnapshot object once one is created so that it can be efficiently reused. This is possible because a only a single async operation is permitted at any time. Access to the cached instance uses interlocked to take the instance so that it cannot ever be used twice and lazily returns the cleared object using standard assignment because creating a new one every now again again isn't a problem as long as it is usually reused. Under load one snapshot was created per reader and reused cleanly.Keep track of a cached
TdsStateParserObjectsnapshot in a similar way toSqlDataReaderbut using interlocked for both rent and return to the cache variable.Use slightly smaller data structures by compressing multiple boolean fields on
TdsParserStateObjectinto a flags enumeration, this makes multiple flags copy and restore a single copy not 5. All access to the affected properties is now done through accessor functions.Introduce a small class
Snapshot.PLPDatato store any partially length prefixed data state if it is used, if it is not used the allocation object object and continual tracking of 128 bits of data it contains are avoided.Change
Snapshot.PacketDatato be a self assembling singly linked list. This removesList<PacketData>and linkedPacketData[]allocations when taking snapshots and allows a cached PacketData link to be retained in the snapshot since one will always be required is a snapshot is used.I also removed most of the setting of
TdsParserStateObjectvariables to default values so it is now easier to tell when they are initialized to non-default values. The only exceptions are some variables which must be initialized to default because they are only touched through reflection in testing so the compiler will complain that it can't see them being set.Profile results before, green are the result objects we actually want:

After:

I have another branch which removes 3 of the 4 intervening async machinery allocations which will give some more gains but they're more modest and it needs a little more polish.
Performance results are good
17% throughput increase and halved variance in query time.
Manual and functional test pass in native mode. DataAccessPerfomance under pure load and profilers has no problems.
/cc area owners @afsanehr, @tarikulsabbir, @Gary-Zh , @David-Engel , people interested in perf @divega @roji @saurabh500