您实际上问的是两个不同的问题:
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,也不是官方支持的,而是非官方支持,通过第三方应用支持.支持这种缓存的最相关的第三方应用包括:
- Johnny-Cache(较旧,不支持Django>;1.6)
- Django-Cachalot(更新版本,支持1.6、1.7,仍在版本1.8中)
- Django-Cacheops(更新版本,支持Python 2.7或3.3+、Django 1.8+和Redis 2.6+(推荐4.0+))
如果您要查找查询缓存,请看一下这些内容,并记住,首先配置文件,找出瓶颈,如果它们造成问题,则进行优化.
真正的问题是,程序员在错误的地点和错误的时间花了太多的时间担心效率;过早的优化是编程中所有邪恶(或者至少是其中的大部分)的根源.唐纳德·努斯.