我正在努力优化django中的ORM查询.我使用连接.查询以查看django为我生成的查询.

假设我有这些型号:

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

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

比方说,当我生成一个特定的网页时,我想显示所有的书,每本书的作者名字都在旁边.另外,我还单独展示了所有的作者.

那么我应该使用

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

这将导致一个连接查询.即使我之前写过一行:

Author.objects.all()

显然,在模板中,我将编写类似于{{book.author.name}}的内容.
所以问题是,当我访问一个外键值(Author)时,如果Django已经拥有来自另一个查询的对象,那么是否仍然会导致额外的查询(针对每本书)? 如果不是,那么在这种情况下,使用SELECT_RELATED实际上是否会产生性能开销?

推荐答案

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

1.使用select_related是否真的会产生性能开销?

您应该看到大约Django Query Cache个文档:

Understand QuerySet evaluation

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

  • QuerySet是懒惰的.

  • 当他们被判断的时候.

  • 数据如何保存在内存中.

因此,总而言之,Django将在内存中缓存在同一QuerySet对象中计算的结果,也就是说,如果您这样做的话:

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中预取作者时,将只命中db一次,所有这些内容都将导致一个数据库查询,其中包含INNER JOIN个.

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

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.本文档也不涉及适用于所有昂贵操作(如general purpose caching)的其他优化技术.

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

你的意思是如果Django做了ORM queries caching,这是一个非常不同的问题.ORM查询缓存,也就是说,如果执行before次查询,然后执行later次相同的查询,如果数据库没有更改,则结果来自缓存,而不是expensive次数据库查找.

答案不是Django,也不是官方支持的,而是非官方支持,通过第三方应用支持.支持这种缓存的最相关的第三方应用包括:

  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+))

如果您要查找查询缓存,请看一下这些内容,并记住,首先配置文件,找出瓶颈,如果它们造成问题,则进行优化.

真正的问题是,程序员在错误的地点和错误的时间花了太多的时间担心效率;过早的优化是编程中所有邪恶(或者至少是其中的大部分)的根源.唐纳德·努斯.

Django相关问答推荐

我希望用户能够预订相同的桌子,但不是在同一时间

无法在 docker 启动Django项目

Django modelform在包含在另一个模板中时不呈现

在 Trunc 的 kind 属性中使用字段

当从 fastapi 发送请求时,Django 无法对 Postgres 执行查询

为什么 timezone.now 在作为默认值应用于 Django 中的 DateField 时显示future 日期

Django 嵌套事务 - with transaction.atomic()

什么时候在 django rest 框架序列化程序中调用创建和更新?

如果上下文中缺少变量,如何使 Django 模板引发错误

Django删除查询集的最后五个以外的所有内容

如何在 django-rest-framework 中为 API 使用 TokenAuthentication

django npm 和 node 包架构

Django:创建索引:非唯一,多列

Django:获取上次用户访问日期

Django:如何在视图中获取格式日期?

Django查询否定

Django 发送邮箱

如何在 Django 中使用动态外键?

Django:根据自定义函数过滤查询

Django 在 css 文件中使用背景图像的方法