#29340: "cache.get_or_set()" extra hits on database
-------------------------------------+-------------------------------------
     Reporter:  hematinik            |                    Owner:  nobody
         Type:                       |                   Status:  new
  Cleanup/optimization               |
    Component:  Core (Cache system)  |                  Version:  2.0
     Severity:  Normal               |               Resolution:
     Keywords:  cache                |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Description changed by hematinik:

Old description:

> I've found out that using {{{cache.get_or_set()}}} causes extra SQL
> queries while using the alternative approach to get a key’s value or set
> a value if the key isn’t in the cache (using "if" statement) works fine
> without extra hits on database.
> it seems the problem appears when you use the {{{cache.get_or_set()}}}
> inside a loop . this is the code to reproduce the problem:
>
> THE MODEL:
>
> {{{
> #!python
>
> class EventManager(models.Manager):
>
>     def get_location(self,event):
>
>         output = cache.get_or_set(
>             'event_location_eID{}'.format(event.pk),
>             event.location,
>             None)
>
>         return output
>
> class Event(models.Model):
>
>     objects = EventManager()
>     location = models.ForeignKey(Location,on_delete = models.CASCADE)
>
> }}}
>
> THE VIEW:
> {{{
> #!python
> def home(request):
>
>     events = cache.get_or_set('all_events',Event.objects.all(),None) #
> this line works fine without extra hits on db
>     locations = []
>
>     for event in events:
>         x = Event.objects.get_location(event) # this line causes extra
> SQL queries while the cache keys already exist
>         locations.append(x)
>
>     return render(request,'index.html',{'locations':locations})
> }}}
>
> THE TEMPLATE:
> {{{
> #!python
> {% for location in locations %}
>
>     {{location.title}} <br>
>
> {% endfor %}
> }}}
>
> now if I change the {{{get_location()}}} method on {{{EventManager}}} to
> this:
>
> {{{
> #!python
> def get_location(self,event):
>
>     output = cache.get('event_location_eID{}'.format(event.pk))
>     if output is None:
>         output = event.location
>         cache.set('event_location_eID{}'.format(event.pk),output,None)
>
>     return output
> }}}
>
> there will be no more unnecessarily SQL queries.
>
> I'm using **django-debug-toolbar** to monitor my database requests and
> the information about queries is based on the statistics that **django-
> debug-toolbar** provides. I'll also attach some screenshots from
> **django-debug-toolbar** to clarify the situation.
>
> Regards.

New description:

 I've found out that using {{{cache.get_or_set()}}} causes extra SQL
 queries while using the alternative approach to get a key’s value or set a
 value if the key isn’t in the cache (using "if" statement) works fine
 without extra hits on database.
 it seems the problem appears when you use the {{{cache.get_or_set()}}}
 inside a loop . this is the code to reproduce the problem:

 THE MODEL:

 {{{
 #!python

 class EventManager(models.Manager):

     def get_location(self,event):

         output = cache.get_or_set(
             'event_location_eID{}'.format(event.pk),
             event.location,
             None)

         return output

 class Event(models.Model):

     objects = EventManager()
     location = models.ForeignKey(Location,on_delete = models.CASCADE)

 }}}

 THE VIEW:
 {{{
 #!python
 def home(request):

     events = cache.get_or_set('all_events',Event.objects.all(),None) #
 this line works fine without extra hits on db
     locations = []

     for event in events:
         x = Event.objects.get_location(event) # this line causes extra SQL
 queries while the cache keys already exist
         locations.append(x)

     return render(request,'index.html',{'locations':locations})
 }}}

 THE TEMPLATE:
 {{{
 #!python
 {% for location in locations %}

     {{location.title}} <br>

 {% endfor %}
 }}}

 now if I change the {{{get_location()}}} method on {{{EventManager}}} to
 this:

 {{{
 #!python
 def get_location(self,event):

     output = cache.get('event_location_eID{}'.format(event.pk))
     if output is None:
         output = event.location
         cache.set('event_location_eID{}'.format(event.pk),output,None)

     return output
 }}}

 there will be no more unnecessarily SQL queries.

 I'm using **django-debug-toolbar** to monitor my database requests and the
 information about queries is based on the statistics that **django-debug-
 toolbar** provides. I'll also attach some screenshots from  **django-
 debug-toolbar** to clarify the situation.

 sql queries when using {{{get_or_set()}}}: [https://imgur.com/a/dydWEuL]
 sql queries when using the alternative approach :
 [https://imgur.com/a/vYpfUZ3]

 Regards.

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29340#comment:1>
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 post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.87fa8f883dff7f40e6c984cae2257108%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to