Thanks, folks, that's a very valuable insight. 
I really love the idea of resolving *OuterRef* via .*join()*, it may help 
overcome problems I had with reusing *Subquery*.
However, I believe *Subquery* exists apart from *QuerySet* for a reason - 
to separate responsibilities, so should we mix responsibilities now with 
Subquery / JoinedSubquery? 

If we reuse Subquery for *QuerySet.join()*, we need a way to refer to the 
columns from that Subquery, and either current *.F(...) *method will be 
added to Subquery, or we need to use named joins ( 
*QuerySet.join(taxes=Subquery(...))* ).
Named joins are problematic, because current implementation of Query can .
*resolve_ref()* (*setup_joins* / *names_to_path*) only to related table OR 
*filtered_relation*. And handling *yet* another case (OR *joined_subquery)* 
will make the branching even more complex.
We could refactor somehow to reduce conditionals usage, but it is not 
something I believe I am capable of.

Yes, it is probably possible to modify existing code, but I am trying to 
avoid adding new paths and conditions here and there - because over time 
such changes will lead to hard to understand codebase no one wants to 
touch. I believe that new behavior is better added via extending, not 
modifications (open-closed principle). There is already some conditional 
handling in ORM (i.e. *filtered_relation*, which can be found in many 
places across whole ORM code, yet it is just one feature (don't get me 
wrong, it's a valuable contribution, I am just worried of a general 
direction), and this way of introducing changes will complicate ORM more 
and more. 

Instead, the suggested solution relies on existing code, but does not 
modify it and is relatively small. 

I will definitely try to create something with *OuterRef*, but I am afraid 
we will end up with: Subquery which actually contains code of two separate 
classes, and several conditional branches (i.e. *if subquery.is_joined*) in 
the QuerySet/Query code.
I will come back with new information as soon as I have time (probably by 
the weekend).

Have a nice day,
Alexandr.

On Tuesday, 7 April 2020 08:39:47 UTC+3, schinckel wrote:
>
> Great work on this, Alexandr. I've been thinking a lot about doing joins 
> in Django to subqueries. As you point out, when you are doing several 
> subquery annotations of the same subquery, just with different columns, 
> that can really hurt performance. Currently, I've been recommending doing a 
> JSON object as the subquery column.
>
> I really like the idea of an explicit join to a subquery, as it can 
> perform significantly better - in the case where most of the rows share the 
> same subquery, the database can perform the subquery once per distinct row 
> joined, rather than once for each row.
>
> I think, instead of using a `JoinedSubquery`, we should just make it that 
> a `Subquery`, containing unresolved OuterRef instances, can also be 
> resolved by doing a `QuerySet.join(Subquery(...))`.
>
> We could also have a lateral argument that allowed a LATERAL JOIN to a 
> subquery, but perhaps that's later down the track.
>
> (Actually, now I think about it, a QuerySet should probably just act as a 
> Subquery when it's used as one, but perhaps that's too magic).
>
> Matt.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/f32053b3-f4e9-4736-ba64-c15d9a62ba25%40googlegroups.com.

Reply via email to