Skip to content

Optimize ParameterExtractingExpressionVisitor #32698

@roji

Description

@roji

ParameterExtractingEV identifies evaluatable fragments in the query tree, and replaces them either with query parameters (if they contain closure captured variables) or with constants (if they don't). This is a perf-critical piece of query infrastructure since it has to run for every query - parameter extraction must happen for each and every query separately.

The current implementation works as follows:

  • Visit the query tree to identify evaluatable nodes (EvaluatableExpressionFindingEV). This is a visitor which populates a dictionary with evaluatable nodes as keys, with the values being whether they should be parameterized or evaluated as constant.
  • Once this first pass is complete, ParameterExtractingEV visits the query tree again, and the moment it finds a node that's in the dictionary, evaluates it. This ensures that the top-most in an evaluatable subtree gets evaluated.

Aside from the double visitation, the population of the dictionary introduces a non-trivial overhead, inserting lots of nodes which won't be needed (only the top-most evaluatable in a given subtree is important).

It's possible to implement the same behavior in a single pass, simply bubbling up evaluatability information from the leaves and evaluating once we reach a node where not all children are evaluatable, but some are. The disadvantage compared to the current design, is that this would require specific logic to be coded for each node type (binary, method...), whereas the current visitor design is more generic (although in practice there are many exceptions/optimizations for specific node types).

Since we are now working on supporting precompiled queries via .NET interceptors, we'll need the ParameterExtractingEV to produce code which extracts (evaluates) parameters from the tree (#32999); this requires specific logic for each node type anyway, in order to generate the path through the expression tree to the evaluatable fragment. At this point we can also implement the more efficient design as well.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions