diff options
author | Simon Charette <charette.s@gmail.com> | 2022-11-09 21:55:47 -0500 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-11-11 08:46:08 +0100 |
commit | a9d2d8d1c36a4338758a792c475965180629a59f (patch) | |
tree | f9265a79d0a80b83e12dafd6bba39d0c85cab07e /django/db/models/sql/query.py | |
parent | 99b4f90ec6b96e8c2a9f22b360d4eb5589763034 (diff) | |
download | django-a9d2d8d1c36a4338758a792c475965180629a59f.tar.gz |
Refs #28477 -- Reduced complexity of aggregation over qualify queries.
Diffstat (limited to 'django/db/models/sql/query.py')
-rw-r--r-- | django/db/models/sql/query.py | 34 |
1 files changed, 20 insertions, 14 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index c9e2960012..775e2668b0 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -447,13 +447,15 @@ class Query(BaseExpression): if alias not in added_aggregate_names } # Existing usage of aggregation can be determined by the presence of - # selected aggregate and window annotations but also by filters against - # aliased aggregate and windows via HAVING / QUALIFY. - has_existing_aggregation = any( - getattr(annotation, "contains_aggregate", True) - or getattr(annotation, "contains_over_clause", True) - for annotation in existing_annotations.values() - ) or any(self.where.split_having_qualify()[1:]) + # selected aggregates but also by filters against aliased aggregates. + _, having, qualify = self.where.split_having_qualify() + has_existing_aggregation = ( + any( + getattr(annotation, "contains_aggregate", True) + for annotation in existing_annotations.values() + ) + or having + ) # Decide if we need to use a subquery. # # Existing aggregations would cause incorrect results as @@ -468,6 +470,7 @@ class Query(BaseExpression): isinstance(self.group_by, tuple) or self.is_sliced or has_existing_aggregation + or qualify or self.distinct or self.combinator ): @@ -494,13 +497,16 @@ class Query(BaseExpression): self.model._meta.pk.get_col(inner_query.get_initial_alias()), ) inner_query.default_cols = False - # Mask existing annotations that are not referenced by - # aggregates to be pushed to the outer query. - annotation_mask = set() - for name in added_aggregate_names: - annotation_mask.add(name) - annotation_mask |= inner_query.annotations[name].get_refs() - inner_query.set_annotation_mask(annotation_mask) + if not qualify: + # Mask existing annotations that are not referenced by + # aggregates to be pushed to the outer query unless + # filtering against window functions is involved as it + # requires complex realising. + annotation_mask = set() + for name in added_aggregate_names: + annotation_mask.add(name) + annotation_mask |= inner_query.annotations[name].get_refs() + inner_query.set_annotation_mask(annotation_mask) relabels = {t: "subquery" for t in inner_query.alias_map} relabels[None] = "subquery" |