|
|
Django ORM performance patchDjango ORM is simple and obvious, but when from tutorial models project moved to real-world models, same ORM often becomes headache. I work on big Django-project that currently have 278 models in 40 applications with a lot of relations between them. For such number of models For example following query it's standard way to receive with 1 SQL query and then show 10 last blog entries titles with author names and avatars.
The problem is in SQL query that Django ORM will generate for this code – it will load from database all fields of A lot of resources wasted here: it's not cheap to select from database big textfield, then transfer utf-8 bytes to web-server, convert from utf-8 to unicode, allocate kilobytes of memory in python process, and finally run garbage collector that will find that those already megabytes of memory (for each object from object list for each client request) were not need at all and it safe now to spend some more system resources for deleting these never used objects. Current Special lightweight models (when you bind to same database table several Django models with different field subsets of a heavy model) results in code duplication and require to implement lightweight models for all related heavy models also, and actually it's not web development done right. Returning back to old good SQL is possible but it's "not right" and in this case you also lose business logic already defined in models. I checked out queryset-ref Django branch and didn't find solution for above problem. This branch makes step ahead and allows to control what related models to join and what don't to join, but it don't give me what I need – full control on the loaded fields without loosing advantages of models. Then I found 2 Django tickets #5420: Allow database API users to specify the fields to exclude in a SELECT statement and #5768: Allow QuerySet.values() to return values spanning joins. This tickets address same problem but unfortunately it were assigned to nobody, so I created the patch and going to attach it to above tickets. You can download the patch here, it is quite simple but allows to write queries that loads only those fields that you requested (and plan to use in view or template). Above example with new
The patch include
Both And a final note about lazy loading of field, that was mentioned in the Django ticket #5420. Proposed patch don't support and from my experience of using Django in big project lazy field loading is a dangerous feature. When different developers write views and templates and same code can be modified by many developers, it's very easy to find eventually in a template single not-optimal line of code that for objects list from 10 items will generate 20 heavy SQL queries. It may look like:
With lazy field loading we can have same problem. For example frontend developer can add to a template I tested the patch with Django trunk in my environment and all 234 available tests were passed. If the patch will broke something in other environments, please let me know in comments. WebAlchemy vs StaticGeneratorWhen two months ago I published WebAlchemy code, several people asked me how to make it working with nginx or lighttpd. Yesterday new tool similar to WebAlchemy StaticGenerator was published. Now it seems right time to explain how to use WebAlchemy with nginx and other servers that don't have I designed WebAlchemy to support publishing of resources of any content type with any URL scheme and ability to be used in RESTful environment when GET-requests to same url are served as static requests, but POST-, PUT- and other requests are served by Django. It means that for example request to /feed/comments/ that also served by WebAlchemy on this site should return Other issue and important difference between WebAlchemy and StaticGenerator is additional load that each tool creates. StaticGenerator generates static versions of changed pages every time when master model is changed and doesn't take into account transaction, so same path may be transformed even several times during a transaction. WebAlchemy don't create additional load on web-server, it don't generates static version especially, but uses generated in result of real user request content (all future requests of this url are served as static). Both WebAlchemy and StaticGenerator use So if you don't want to use When content types issues are resolved, you can use WebAlchemy with any web-server. You just need to use your trivial publisher that don't deal with
Nothing in original WebAlchemy core code was changed so you can use it. Link to source code and instructions for WebAlchemy configuration you can find at original blog entry WebAlchemy accelerates Django in 100 times. |
Web log, research lab and soft parade of Dima Dogadaylo.
Email: entropyhacker at gmail dot com |
| [about | blog | projects]
© Dima Dogadaylo |
|