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

Performance: Adds a LINQ optimization for member access in LINQ-to-SQL #2924

Merged
merged 9 commits into from
May 4, 2022

Conversation

notheotherben
Copy link
Member

Pull Request Template

Description

This optimization handles the common case of accessing a member (variable, field, property) in the ambient scope, as shown below:

var bob = "Bob";
users.Where(u => u.Username == bob);

In this scenario, we will attempt to avoid compiling a lambda expression to evaluate bob and instead rely on reflection member access to retrieve the constant value. This helps us avoid the global lock held by System.Reflection.Emit.DynamicMethod while constructing the dynamic method table, which alleviates a serious performance bottleneck on highly threaded systems. In particular, this helps avoid a pathological async-over-sync situation which can lead to thread pool exhaustion and hot-lock thrashing.

The goal of this change is to provide teams who face this problem with a reasonable means of optimizing their query code (use variables which hold pre-computed constants to avoid delegate compilations), instead of forcing them to rewrite their codebases to use stored SQL, or to implement some form of SQL caching.

Type of change

  • New feature (non-breaking change which adds functionality)

Copy link

@ndrwrbgs ndrwrbgs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall comment:
Is the underlying problem here isolated to Constants? I think this change could help in the scenario that is currently your focus - but is there anything more architecturally that could/should be changed to accommodate a large class of issues?

Microsoft.Azure.Cosmos/src/Linq/SubtreeEvaluator.cs Outdated Show resolved Hide resolved
@ealsur
Copy link
Member

ealsur commented Dec 8, 2021

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@j82w
Copy link
Contributor

j82w commented Dec 9, 2021

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

j82w
j82w previously approved these changes Dec 10, 2021
@j82w
Copy link
Contributor

j82w commented Dec 10, 2021

@khdang and @sboshra and @timsander1 please review this PR.

ndrwrbgs
ndrwrbgs previously approved these changes Dec 11, 2021
@j82w j82w changed the title feat: Implement an optimized path for member access in LINQ-to-SQL Performance: Adds a LINQ optimization for member access in LINQ-to-SQL Dec 13, 2021
@@ -42,14 +43,59 @@ protected override Expression VisitMemberInit(MemberInitExpression node)
return node;
}

private Expression EvaluateMemberAccess(Expression expression)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please add functional test to cover this function so the target scenarios of this change are clear?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @khdang, I can certainly add some further tests which exercise this code path, however they'll be identical to the existing test suite.

This code change is responsible for handling any .x.y.z property accesses, which would previously have required the compilation and invocation of a delegate. Given that ambient variables are captured in an implicit structure, this applies to any query which attempts to pattern match to an ambient variable.

As such, this acts as a transparent performance optimization for this (very) common use case without any external behavioural changes. Paired with the fact that the list of expressions which are evaluated is pre-filtered, and I suspect that it should be very rare indeed that this code path is not followed (which is a good thing given the performance and concurrency benefits).

notheotherben and others added 7 commits April 28, 2022 10:18
…n a LINQ-to-SQL expression

This optimization handles the common case of accessing a member (variable,
field, property) in the ambient scope, as shown below:

```
var bob = "Bob";
users.Where(u => u.Username == bob);
```

In this scenario, we will attempt to avoid compiling a lambda expression to
evaluate `bob` and instead rely on reflection member access to retrieve the
constant value. This helps us avoid the global lock held by
`System.Reflection.Emit.DynamicMethod` while constructing the
dynamic method table, which alleviates a serious performance bottleneck
on highly threaded systems.

In particular, this helps avoid a pathological async-over-sync situation
which can lead to thread pool exhaustion and hot-lock thrashing.
@notheotherben notheotherben dismissed stale reviews from ndrwrbgs and j82w via 78ff617 April 28, 2022 09:32
@notheotherben notheotherben force-pushed the feature/linq-sql-member-access branch from 2d3ef47 to 78ff617 Compare April 28, 2022 09:32
@notheotherben notheotherben requested a review from khdang April 28, 2022 09:44
@khdang
Copy link
Member

khdang commented May 4, 2022

Thanks @notheotherben for doing this optimization!

@j82w
Copy link
Contributor

j82w commented May 4, 2022

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

@j82w j82w enabled auto-merge (squash) May 4, 2022 17:39
@j82w j82w merged commit 924c2e7 into Azure:master May 4, 2022
@notheotherben
Copy link
Member Author

Thanks for getting this merged folks, I suspect this should have a pretty sizeable benefit for our user-base.

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.

5 participants