Skip to content

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

Merged
j82w merged 9 commits into
Azure:masterfrom
notheotherben:feature/linq-sql-member-access
May 4, 2022
Merged

Performance: Adds a LINQ optimization for member access in LINQ-to-SQL#2924
j82w merged 9 commits into
Azure:masterfrom
notheotherben:feature/linq-sql-member-access

Conversation

@notheotherben
Copy link
Copy Markdown
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
Copy Markdown

@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?

Comment thread Microsoft.Azure.Cosmos/src/Linq/SubtreeEvaluator.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/Linq/SubtreeEvaluator.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/Linq/SubtreeEvaluator.cs Outdated
Comment thread Microsoft.Azure.Cosmos/src/Linq/SubtreeEvaluator.cs Outdated
@ealsur
Copy link
Copy Markdown
Member

ealsur commented Dec 8, 2021

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

@j82w
Copy link
Copy Markdown
Contributor

j82w commented Dec 9, 2021

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

j82w
j82w previously approved these changes Dec 10, 2021
@j82w
Copy link
Copy Markdown
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
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Member

khdang commented May 4, 2022

Thanks @notheotherben for doing this optimization!

@j82w
Copy link
Copy Markdown
Contributor

j82w commented May 4, 2022

/azp run

@azure-pipelines
Copy link
Copy Markdown

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
Copy Markdown
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