-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Translate parameterized collections to inline collections of parameters, with optional bucketization #34346
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
Comments
This seems like a very good idea |
How are you planning to implement this "bucketization"? Would the "bucket size" (e.g. 5 in the example) be specified by the end-user on a per-method-call basis, or as a configuration option in the |
I have shared this implementation for years, based on a proposal from @divega https://gist.github.com/ErikEJ/6ab62e8b9c226ecacf02a5e5713ff7bd |
I also blogged about this years ago here: https://erikej.github.io/efcore/sqlserver/2020/03/30/ef-core-cache-pollution.html |
This might also be useful (for SQL Server) https://github.com/dotnet/SqlClient/blob/main/release-notes/4.0/4.0.0.md#enable-optimized-parameter-binding |
@IanKemp we'd probably provide both a context option to configure the default bucket size, and also a per-collection configuration as well - similar to how we're implementing context-wide and per-collection configurability for constantization/parameterization in 9 (see #32394 (comment)). Note that this technique needs to be compared with just going back to full constantization, but with SQL Server RECOMPILE (see #34347). Inline collection with parameters does allow caching query plans where the collection cardinality is the same, but may also have some performance drawbacks and still causes some plan bloat (for different cardinalities). |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Good point by @cincuranet: this technique can hit the SQL Server 2100 parameter limit. |
@roji Yes, in the case of 2084 parameters, the user will have to bucket the values. |
When a collection parameter is referenced in a LINQ query, we currently allow it to be either parameterized in SQL (e.g. converted to a JSON array and processed with OPENJSON), or constantized (constant values integrated as-is in the SQL). Each method has its advantages and disadvantages (constantized queries allow for better query plans, parameterized queries have a single SQL and are better for plan/query caching).
A 3rd mode would be to integrate the values as SQL parameters, into an inline SQL collection (e.g.
IN (@p1, @p2, @p3)
; this would allow the database the ability to take the collection's cardinality when planning (like the constantization option). As a further optimization on top, to partially mitigate the different-SQLs problem for collections of varying sizes, we'd have different sizing steps (or "buckets", e.g. 1, 5, 10, 20...); collections with e.g. 3 items would have their last item repeated to arrive at the next bucket size (5).Notes:
Where(b => new[] { p1, p2, p3 }
; but this works only if the size is fixed in the .NET collection. This issue is about having EF produce the same SQL but for when the entire .NET collection is parameterized in the LINQ query.The text was updated successfully, but these errors were encountered: