Skip to content
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

Reduce lambda compilation for constant evaluation #375

Merged
merged 1 commit into from
Sep 11, 2024

Conversation

brantburnett
Copy link
Collaborator

@brantburnett brantburnett commented Aug 30, 2024

Motivation

We are seeing significant, ongoing JIT compilations and allocations as a result of evaluating constants during the query generation process. Almost all queries include some reference to a local variable as part of the expression tree, such as a reference to the IQueryable itself or a filter variable in a Where predicate. These local variables are captured as a closure by C# under the covers, and appear as MemberAccessExpression with a ConstantExpression as the target. Currently, such cases require the JIT compilation of a lambda for every single execution of the query.

Modifications

Create an EnhancedPartialEvaluatingExpressionTreeVisitor based upon the Relinq PartialEvaluatingExpressionTreeVisitor that evaluates more cases using reflection instead of compiling a lambda. This includes the mentioned member access case as well as some other common cases. Expressions which can't be evaluated in this manner fallback to the previous behavior of compiling a lambda and executing it.

Results

Significantly less overhead for most queries when computing the constant portions of the query. Note that in this context constant means a the portion of the query that is known and evaluatable within C# without requiring data from the database. It does not necessarily mean that the values are constant for each execution of the query.

Motivation
----------
We are seeing significant, ongoing JIT compilations and allocations as
a result of evaluating constants during the query generation process.
Almost all queries include some reference to a local variable as part
of the expression tree, such as a reference to the IQueryable<T> itself
or a filter variable in a Where predicate. These local variables are
captured as a closure by C# under the covers, and appear a
MemberAccessExpression with a ConstantExpression as the target.
Currently, such cases require the JIT compilation of a lambda for
every single execution of the query.

Modifications
-------------
Create an EnhancedPartialEvaluatingExpressionTreeVisitor based upon
the Relinq PartialEvaluatingExpressionTreeVisitor that evaluates more
cases using reflection instead of compiling a lambda. This includes the
mentioned member access case as well as some other common cases.
Expressions which can't be evaluated in this manner fallback to the
previous behavior of compiling a lambda and executing it.

Results
-------
Significantly less overhead for most queries when computing the
constant portions of the query. Note that in this context constant means
a the portion of the query that is known and evaluatable within C#
without requiring data from the database. It does not necessarily mean
that the values are constant for each execution of the query.
@jeffrymorris jeffrymorris merged commit fd1508d into master Sep 11, 2024
1 check passed
@brantburnett brantburnett deleted the constant-evaluation branch September 13, 2024 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants