#33672: bulk_update - duplicate updates as side effect from batch_size
-------------------------------------+-------------------------------------
               Reporter:  jerch      |          Owner:  nobody
                   Type:             |         Status:  new
  Cleanup/optimization               |
              Component:  Database   |        Version:  4.0
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 While trying to mimick `bulk_update` behavior for `fast_update` I stumbled
 over duplicate updates from different batch_size. To illustrate the issue:

 {{{
 #!div style="font-size: 80%"
 Code highlighting:
   {{{#!python
   >>> from exampleapp.models import Foo
   >>> from django.db import connection
   >>> Foo.objects.all().values('pk')
   <QuerySet [{'pk': 1}, {'pk': 2}, {'pk': 3}, {'pk': 4}]>
   >>> pks=[1,2,3,3,2,2,1,1,4]
   >>> objs=[Foo(pk=pk) for pk in pks]
   >>> Foo.objects.bulk_update(objs, ['f1'])  # within batch_size: all
 duplicates filtered
   >>> connection.queries[-1]['sql']
   'UPDATE "exampleapp_foo" SET "f1" = <CASE chain shortened...> WHERE
 "exampleapp_foo"."id" IN (1, 2, 3, 4)'
   >>> Foo.objects.bulk_update(objs, ['f1'], batch_size=4)  # multiple
 batches
   >>> connection.queries[-1]['sql']
   'UPDATE "exampleapp_foo" SET "f1" = <CASE chain shortened...> WHERE
 "exampleapp_foo"."id" IN (4)'
   >>> connection.queries[-2]['sql']
   'UPDATE "exampleapp_foo" SET "f1" = <CASE chain shortened...> WHERE
 "exampleapp_foo"."id" IN (2, 1)'
   >>> connection.queries[-3]['sql']
   'UPDATE "exampleapp_foo" SET "f1" = <CASE chain shortened...> WHERE
 "exampleapp_foo"."id" IN (1, 2, 3)'
   }}}
 }}}

 The example above requests a bulk update for a degenerated pk list with
 duplicates `[1,2,3,3,2,2,1,1,4]`. `batch_size` now has a weird effect on
 which updates "get through":
 - all within one batch - update  done `[[1,2,3,4]]`
 - scattered across batches with `batch_size=4` - updates done `[[1,2,3],
 [2,1], [4]]`

 I understand the need to drop duplicates at a single UPDATE invocation
 (need that for `fast_update` as well), but isn't the current behavior
 surfacing a side effect of an implementation detail here? Imho that
 behavior is hard to anticipate/control by the user.

 Idea/suggestion:
 How about treating this more unique/atomic at the `bulk_update` call level
 by either doing:
 - filter duplicates for the whole changeset (automatic filtering might
 still be surprising for users)
 - or disallow/raise for any duplicate in a changeset (would prefer that
 for code simplicity and more clear behavior)

 With such a change `bulk_update` would always exhibit the same behavior
 for a given changeset, regardless of `batch_size`.

 (Categorized this as cleanup/optimization, since the unlucky behavior is
 documented.)

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33672>
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 unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018079ca70a8-73f2981e-39b3-4faf-9097-ec2b2938bcca-000000%40eu-central-1.amazonses.com.

Reply via email to