django select_related-何时使用 [英] django select_related - when to use it

查看:73
本文介绍了django select_related-何时使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Django中优化我的ORM查询.我使用connection.queries查看django为我生成的查询.

I'm trying to optimize my ORM queries in django. I use connection.queries to view the queries that django generate for me.

假设我有以下模型:

class Book(models.Model):
    name   = models.CharField(max_length=50)
    author = models.ForeignKey(Author)

class Author(models.Model):
    name   = models.CharField(max_length=50)

比方说,当我生成一个特定的网页时,我想显示所有书籍,并在每本书旁边加上作者姓名.另外,我单独显示所有作者.

Let's say, when I generate a specific webpage, I want to display all books, with their author name next to each of them. Also, I display seperately all the authors.

我应该使用

Book.objects.all().select_related("author")

这将导致JOIN查询.即使我之前做过一行:

Which will result in a JOIN query. Even if I do a line before:

Author.objects.all()

很显然,在模板中,我将编写类似{{book.author.name}}的内容.
所以问题是,当我访问一个外键值(作者)时,如果django已经从另一个查询中获得了该对象,那还会导致额外的查询(针对每本书)吗? 如果否,那么在这种情况下,使用select_related实际上会产生性能开销吗?

Obviously in template I will write something like {{book.author.name}}.
So the question is, when I access a foreign key value (author), if django already has that object from another query, will that still result in additional query (for each book)? If no, so in that case, does using select_related actually creates performance overhead?

推荐答案

您实际上是在问两个不同的问题:

You are actually asking two different questions:

您应该看到有关 Django查询缓存:

了解QuerySet评估

为避免性能问题,重要的是要了解:

To avoid performance problems, it is important to understand:

  • 查询集是惰性的.

  • that QuerySets are lazy.

在评估它们时.

数据如何保存在内存中.

how the data is held in memory.

因此,总而言之,Django将在同一QuerySet对象中评估的内存结果缓存在内存中,也就是说,如果您执行以下操作:

So in summary, Django caches in memory results evaluated within the same QuerySet object, that is, if you do something like that:

books = Book.objects.all().select_related("author")
for book in books:
    print(book.author.name)  # Evaluates the query set, caches in memory results
first_book = books[1]  # Does not hit db
print(first_book.author.name)  # Does not hit db  

当您在select_related中预取了Authors时,只会打一次db,所有这些东西将导致使用 INNER JOIN 进行单个数据库查询.

Will only hit db once as you prefetched Authors in select_related, all this stuff will result in a single database query with INNER JOIN.

但这不会在查询集之间进行任何缓存,甚至对于相同的查询也不会进行缓存:

BUT this won't do any cache between querysets, nor even with the same query:

books = Book.objects.all().select_related("author")
books2 = Book.objects.all().select_related("author")
first_book = books[1]  # Does hit db
first_book = books2[1]  # Does hit db

这实际上在 docs :

我们将假定您已完成上述显而易见的操作.本文档的其余部分重点介绍如何以不执行不必要工作的方式使用Django.本文档也未涉及适用于所有昂贵操作的其他优化技术,例如常规用途缓存.

2.如果django已经从另一个查询中获得了该对象,是否还会导致其他查询(针对每本书)?

您实际上是在说Django是否进行 ORM查询缓存,这是非常不同的事情. ORM查询缓存,即,如果您先进行之前的查询,然后再进行相同的查询以后,如果数据库未更改,则结果来自缓存而不是通过昂贵的数据库查找.

2. if django already has that object from another query, will that still result in additional query (for each book)?

You are actually meaning if Django does ORM queries caching, which is a very different matter. ORM Queries caching, that is, if you do a query before and then you do the same query later, if database hasn't changed, the result is coming from a cache and not from an expensive database lookup.

答案不是Django,没有得到官方支持,但是非正式地,是通过3rd-party应用程序.启用这种类型的缓存的最相关的第三方应用程序是:

The answer is not Django, not officially supported, but yes unofficially, yes through 3rd-party apps. The most relevant third-party apps that enables this type of caching are:

  1. Johnny-Cache (较早,不支持django> 1.6)
  2. Django-Cachalot (较新,支持1.6、1.7,并且仍在开发版1.8中)
  3. Django-Cacheops (较新,支持Python 2.7或3.3 +,Django 1.8+和Redis 2.6+(建议4.0 +))
  1. Johnny-Cache (older, not supporting django>1.6)
  2. Django-Cachalot (newer, supports 1.6, 1.7, and still in dev 1.8)
  3. Django-Cacheops (newer, supports Python 2.7 or 3.3+, Django 1.8+ and Redis 2.6+ (4.0+ recommended))

如果您要查找查询缓存并记住这些信息,请首先查看配置文件,查找瓶颈,如果它们引起了问题,则进行优化.

Take a look a those if you look for query caching and remember, first profile, find bottlenecks, and if they are causing a problem then optimize.

真正的问题是程序员花了太多时间来担心在错误的地方和错误的时间的效率.过早的优化是编程中所有邪恶(或至少是大多数邪恶)的根源.唐纳德·克努斯(Donald Knuth).

The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming. Donald Knuth.

这篇关于django select_related-何时使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆