Fix for #34117, Improve Hash Code Distribution for RelationalCommandCache Keys#34118
Conversation
…Code Switched to RuntimeHelpers.GetHashCode over .GetHashCode to avoid any overridden GetHashCode methods that might need additional processing to propagate hash calculations down the expression tree.
roji
left a comment
There was a problem hiding this comment.
Thanks... Good catch on the perf issue, and the fix looks good. This will bucketize RelationalCommandCache entries based on their query expressions, which is indeed an improvement.
Note that we can create more high-quality keys by also including parameter nullability information in the hashcode, exactly as the Equals method does. As the PR currently is, all entries for a given query are bucketized together (since there's no parameter nullability differentiation in the hashcode), and so there will be linear searching between the different cache entries for the query. If we include parameter nullability, that would be improved.
Let me know if this makes sense to you and is something you want to implement in this PR; if not, I'm still fine with merging it as it's a clear improvement over the existing situation.
|
I'm good with this, I understand the additions you are referring to but will leave those as an improvement for when time allows. Thanks. |
This PR addresses a performance issue in the RelationalCommandCache class where the CommandCacheKey struct uses a hard-coded GetHashCode implementation that returns 0. This implementation leads to all instances being placed in the same bucket within the MemoryCache's internal ConcurrentDictionary, causing linear search times and negating the performance benefits of the hash-based collection.
See Issue #34117
Changes
Modified the GetHashCode implementation in the CommandCacheKey struct to use RuntimeHelpers.GetHashCode(_queryExpression).
Ensured that the new implementation maintains the contract with the overridden Equals method, which first checks for reference equality.