#18676: Django should do m2m deletes in a single query when possible
-------------------------------------+-------------------------------------
     Reporter:  jdunck               |                    Owner:  nobody
         Type:                       |                   Status:  new
  Cleanup/optimization               |                  Version:  1.4
    Component:  Database layer       |               Resolution:
  (models, ORM)                      |             Triage Stage:  Accepted
     Severity:  Normal               |      Needs documentation:  0
     Keywords:                       |  Patch needs improvement:  0
    Has patch:  1                    |                    UI/UX:  0
  Needs tests:  0                    |
Easy pickings:  0                    |
-------------------------------------+-------------------------------------

Comment (by akaariai):

 Some bugs optimizations done in the above branch. I know there is still
 more to do in !DeleteQuery.delete_qs() - at least the logic for primary
 key table alias selection isn't valid - there is no guarantee that the
 get_initial_alias() contains the pk field.

 I did some little benchmarking, the models:
 {{{
 class Place:
     name = TextField

 class AA:
     place = ForeignKey(Place, null=True)
 }}}

 The tests are: create 0, 1, 10, or 100 AA and delete with
 AA.objects.all().delete(), and similarly 0, 1, 10 or 100 AA objects, this
 time deleted with AA.objects.filter(`place__name='p'`).delete(). The first
 test hits the single-table delete in delete_qs, the second case hits the
 joined delete in delete_qs.

 The speed results for PostgreSQL are as follows:

 ||test||master||fast_delete||
 ||all, 0||.203827||.155007||
 ||all, 1||..314117||.157289||
 ||all, 10||.371872||.153490||
 ||all, 100||.878677||.203811||
 ||filter, 0||.476457||.545436||
 ||filter, 1||.468119||.503444||
 ||filter, 10||.569284||.503499||
 ||filter, 100||1.356935||.693341||

 So, on all but joined filter with 0 or 1 deleted object the patch is
 faster. There is some variance in the results, as can be seen from the
 .545 result for the 0 object filter case. That result is usually faster
 than the case with one object.

 The reason for the speed difference is that the delete query with an inner
 join is a little slow for the 0 objects case, and there is some extra
 overhead from query.clone() in the inner join case.

 The relative speeds are similar on in-memory SQLite.

 The above test-case is favouring the old behaviour of fetching all the
 objs into memory, as there isn't actually any data. For large deletes we
 have a clear win. For small deletes we have minor improvement in the non-
 joined case, and a minor loss for the joined case. For huge deletes it is
 easy to construct arbitrarily large differences in speed.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/18676#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to