toastdriven/django-tastypie — pull request #525 by maraujop (2012-06-13 16:57:38+00:00)
Title: Speeding up PUTs and PATCHs

Hi there,

We are using partial PUTs (which are out of the REST spec, we know) and we've realized that regular PUTs are doing quite a big number of queries.

In the provided patch, which is passing tests, `medium_hydrate` is only iterating over `bundle.data` thus only hydrates fields that changed (Remember we are not passing a full representation of the resource, only partial data that changed).

This is giving us a huge speedup for partial PUTs, forgetting the HTTP throughput speedup and taking only the DB into account, we are now updating a resource in 45ms, when it was taking 750ms.

### Some background

First, we realized that `obj_create` may do two `full_hydrate` calls (from what we've seen one of the most expensive calls in `ModelResource'). As you know, this popullates a `bundle.obj` using `bundle.data`. If your ModelResource has some FKs, you might even see `number_of_fks * 2` queries.

After `get_obj_list` (no matter if it works or not), an `obj_get` is done, selecting the same object again. why query twice to get an object from a DB for updating it? are we missing something?

Then `save_related` is executed, no matter if FKs have been modified, and they same happens to M2Ms with their correspondent hydrating, which isn't cheap either.

So for example, one PUT to a resource with 3 FKs produces:

* 2 SELECTs for grabbing the instance that is modified by PUT
* 3 SELECTs (`get_obj_list` fails, otherwise it would be 6) for gathering the information of the object, that we already have.
* Then several saves that are unnecessary as we are only modifying a boolean field. This might be bug #397

So, we thought about using PATCH, which is the right way to do partial updates. But `patch_detail` flow is very similar to `put_detail`'s, and the same queries seem to happen.

Probably, this patch isn't going to get merged into Tastypie's core, but we wanted to raise an issue regarding the performance of PUT being far from optimal.

Maybe, it would be a better approach to find attributes that have changed between `bundle.obj` and `bundle.data` and only work with those, avoiding unnecessary queries.

This patch could also be easily adapted to `patch_detail`. But, we thought that since partial PUTs are already supported in Tastypie (most likely as a side effect), it would be nice to speed them up.

Cheers,
Miguel