On Mon, Sep 26, 2011 at 9:50 PM, Luke Plant <l.plant...@cantab.net> wrote:
> Hi all, > > I finally got fed up with the common performance problem of ending up > doing O(n) DB queries when you need the (many) related objects of a list > of objects, and did something about it: > > https://code.djangoproject.com/ticket/16937 > > I'm pretty sure the concept is something desirable, the problem is the > implementation. > > It is much uglier than I'd like, but I think the current way that > QuerySets/Managers/related managers interact make this inevitable. > > The current behaviour also makes any kind of 3rd party monkey patching > solution extremely hard. For example, the related object descriptors > make it pretty hard to decorate instances of the queryset with some > proxy objects, because they intercept any assignment of attributes of > the same name. (i.e. if you have foo.bar_set, you can't do foo.bar_set > == some_precalculated_objects as a performance hack). And the way the > descriptors work mean that you get new manager objects (even new manager > *classes*) every time you access the property, and this really works > against any kind of monkey patching. > > If you want to implement this outside core, and you don't want to change > templates and other code, I think you'd have to create a proxy for the > entire model instance, and I imagine it would be a total pain. > > So, given how common this performance problem is, and how hard it is to > implement outside core, I think we should consider even an ugly > implementation. I think it is also inevitable that it is going to > involve QuerySet/related managers hacking each other's internals, or > duplicating to some extent. In my implementation, I put most of the > ugliness into QuerySet, and a few hooks into related managers. It might > be possible to clean it up a bit. > > There is also a fairly nasty use of .extra() which is needed so that > after we retrieve M2M related objects in bulk we know which row on the > primary table they refer to. > > I've got tests and docs in the patch on the ticket. I would say it is > more than proof-of-concept at this stage, but probably less than > finished patch - I may have forgotten some cases that we need to cover. > > Feedback welcome! > > Regards, > > Luke > > -- > "I spilled spot remover on my dog. Now he's gone." (Steven Wright) > > Luke Plant || http://lukeplant.me.uk/ > > -- > You received this message because you are subscribed to the Google Groups > "Django developers" group. > To post to this group, send email to django-developers@googlegroups.com. > To unsubscribe from this group, send email to > django-developers+unsubscr...@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/django-developers?hl=en. > > I'm not a fan of this, for a few reasons, firstly: because it feels wrong for a QuerySet to execute multiple queries. This isn't a deal breaker, just something that struck my conceptually initially. Second I disagree that it's difficult to do outside of core, it's not as easy as it ought to be, but it's very possible (citation: I've done it :)). Finally (for now ;)) it doesn't feel right for something inside core to have caveats like "only works if you use .all()", there's a very good technical reason for this, but something about it is irking me the wrong way. Needs more thought by me'ly yours, Alex -- "I disapprove of what you say, but I will defend to the death your right to say it." -- Evelyn Beatrice Hall (summarizing Voltaire) "The people's good is the highest law." -- Cicero -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.