-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Query : client-side result operators may cause extensive client-side evaluation for queries with GroupJoins (and/or optional navigations) in a subquery #7476
Comments
Problem here is that when we visit subquery model we optimize GroupJoins out (remove SelectMany-DefaultIfEmpty clauses that follow GroupJoin), however when we encounter client side (result) operator throw all that work away and do a second pass (on the already modified query model). Now, because the shape of query model is different, we fail to recognize the GroupJoin-SelectMany-DefaultIfEmpty pattern, which results in GroupJoin being performed on the client. This issue was likely present before, but was exacerbated by #7348 (where we forced client evaluation on some result operators for GroupJoin scenarios) |
…ve client-side evaluation for queries with GroupJoins (and/or optional navigations) in a subquery When we translate GroupJoin-SelectMany-DefaultIfEmpty we modify query model - we remove additional from clause containing DefaultIfEmpty subquery. However, if we later discover that the subquery (or a subquery higher in the stack) needs client evaluation - e.g. by having client result operator, or calling a client-side method - we need to re-visit this subquery with client evaluation in mind. Problem was that now the query model has been modified - in this specific case SelectMany-DefaultIfEmpty clause has been removed, so we can no longer recognize that this pattern can be simplified and we introduce client GroupJoin. Fix is to save the structure of query model (and all subquery models that it contains) before we visit it - and then, if client evaluation is needed, restore the query model to it's original shape.
…ve client-side evaluation for queries with GroupJoins (and/or optional navigations) in a subquery When we translate GroupJoin-SelectMany-DefaultIfEmpty we modify query model - we remove additional from clause containing DefaultIfEmpty subquery. However, if we later discover that the subquery (or a subquery higher in the stack) needs client evaluation - e.g. by having client result operator, or calling a client-side method - we need to re-visit this subquery with client evaluation in mind. Problem was that now the query model has been modified - in this specific case SelectMany-DefaultIfEmpty clause has been removed, so we can no longer recognize that this pattern can be simplified and we introduce client GroupJoin. Fix is to save the structure of query model (and all subquery models that it contains) before we visit it - and then, if client evaluation is needed, restore the query model to it's original shape.
…ve client-side evaluation for queries with GroupJoins (and/or optional navigations) in a subquery When we translate GroupJoin-SelectMany-DefaultIfEmpty we modify query model - we remove additional from clause containing DefaultIfEmpty subquery. However, if we later discover that the subquery (or a subquery higher in the stack) needs client evaluation - e.g. by having client result operator, or calling a client-side method - we need to re-visit this subquery with client evaluation in mind. Problem was that now the query model has been modified - in this specific case SelectMany-DefaultIfEmpty clause has been removed, so we can no longer recognize that this pattern can be simplified and we introduce client GroupJoin. Fix is to save the structure of query model (and all subquery models that it contains) before we visit it - and then, if client evaluation is needed, restore the query model to it's original shape.
Adding to 1.1.1 since we need to fix this before we can tackle #7290 |
@divega Impact: Medium. This is effectively the same issue as #7198, which is a breaking change introduced in 1.1.0 and was reported by a customer. Issue results is inefficient queries for simple cases and compilation errors for complex ones (no data corruption). Risk: Low. Fix is local, we are undoing modifications to query model that we perform during query processing, if the same query model needs to be processed again (effectively “repairing” query model from its corrupted state) |
…ve client-side evaluation for queries with GroupJoins (and/or optional navigations) in a subquery When we translate GroupJoin-SelectMany-DefaultIfEmpty we modify query model - we remove additional from clause containing DefaultIfEmpty subquery. However, if we later discover that the subquery (or a subquery higher in the stack) needs client evaluation - e.g. by having client result operator, or calling a client-side method - we need to re-visit this subquery with client evaluation in mind. Problem was that now the query model has been modified - in this specific case SelectMany-DefaultIfEmpty clause has been removed, so we can no longer recognize that this pattern can be simplified and we introduce client GroupJoin. Fix is to save the structure of query model (and all subquery models that it contains) before we visit it - and then, if client evaluation is needed, restore the query model to it's original shape.
fixed in c8d984e |
This patch bug is approved. Please use the normal code review process w/ a PR and make sure the fix is in the correct branch, then close the bug and mark it as done. |
✅ Verified |
…or complex queries with with subqueries, if the same subquery is present multiple times in the query model Problem was that when we fixed #7476 we introduced a mechanism to copy and then restore query models to prevent them from being corrupted during (failed) attempt at translating them to SQL. However we have not accounted for the case where the same subquery would be present in the query model more than once (same reference). Fix is to add defensive check to the logic that creates a copy of a query model. If we already copied that particular (sub)query model, we don't need to do it twice. It is safe to do, because all occurrences of the query model that share the same reference are guaranteed to have the same body clauses and therefore can later be re-created from the same copy.
…or complex queries with with subqueries, if the same subquery is present multiple times in the query model Problem was that when we fixed #7476 we introduced a mechanism to copy and then restore query models to prevent them from being corrupted during (failed) attempt at translating them to SQL. However we have not accounted for the case where the same subquery would be present in the query model more than once (same reference). Fix is to add defensive check to the logic that creates a copy of a query model. If we already copied that particular (sub)query model, we don't need to do it twice. It is safe to do, because all occurrences of the query model that share the same reference are guaranteed to have the same body clauses and therefore can later be re-created from the same copy.
query:
produces the following query plan:
However, very similar query (Distinct swapped for Take):
produces much more effective query plan:
The text was updated successfully, but these errors were encountered: