You are actually asking two different questions:
1. does using select_related actually creates performance overhead?
You should see documentation about Django Query Cache:
Understand QuerySet evaluation
To avoid performance problems, it is important to understand:
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
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
This is actually pointed out in docs:
We will assume you have done the obvious things above. The rest of this document focuses on how to use Django in such a way that you are not doing unnecessary work. This document also does not address other optimization techniques that apply to all expensive operations, such as general purpose caching.
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.
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:
- Johnny-Cache (older, not supporting django>1.6)
- Django-Cachalot (newer, supports 1.6, 1.7, and still in dev 1.8)
- 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.
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.