我有两个模型,Author
和Book
:
class Author(models.Model):
name = models.CharField(max_length=256)
class Book(models.Model):
name = models.CharField(max_length=256)
price = models.IntegerField()
publication_date = models.DateField()
author = models.ForeignKey(Author, related_name="books")
现在当我得到一组作者和他们的书时,我想用两个值来注释每本书,这两个值表明它是同一作者的过滤书中最便宜或最昂贵的。
我使用Exists
和注释
filtered_books = Book.objects.filter(publication_date__year=2010)
lower_price = filtered_books.only('id').filter(price__lt=OuterRef('price'), author=OuterRef('author'))
higher_price = filtered_books.only('id').filter(price__gt=OuterRef('price'), author=OuterRef('author'))
filtered_books = filtered_books.annotate(
lowest_price=~Exists(lower_price),
highest_price=~Exists(higher_price),
)
authors = Author.objects.annotate.prefetch_related(Prefetch('books', queryset=filtered_books))
它可以工作,但会导致三个(lower_price
,higher_price
和预取)非常相似的子查询被执行并且不那么快。我该如何优化呢?
答案 0 :(得分:1)
现在当我得到一组作者和他们的书时,我想要注释 每本书都有两个值,表明它是最便宜的还是最多的 来自同一作者的过滤书中的价格昂贵。
它有效,但结果有三个(lower_price,higher_price和 prefetch)执行非常相似的子查询,并不是那么快。 我该如何优化呢?
您无法从这3个查询中逃脱,它们将被展示出来 以某种形式。
有3个类似的查询并不意味着它们比单个查询慢3倍,这需要更多的调查才能找到瓶颈的位置,它可能是缺失的索引或smt else。
指示您是否需要将图书价格与某些最低/最高价格进行比较,这是一本最便宜或最便宜的图书。一旦达到最低/最高价格,比较就很容易了。由于您希望将这本书与作者在查询集中的其他书籍进行比较,因此在作者查询集中对此更有意义。一个例子:
filtered_books = Book.objects.filter(publication_date__year=2010)
min_price_subquery = (filtered_books
.filter(author=OuterRef('pk'))
.values('author')
.annotate(min_price=Min('price'))
.only('min_price')
)
max_price_subquery = (filtered_books
.filter(author=OuterRef('pk'))
.values('author')
.annotate(max_price=Max('price'))
.only('max_price')
)
authors = Author.objects.annotate(
min_book_price=Subquery(min_price_subquery, output_field=models.IntegerField()),
max_book_price=Subquery(max_price_subquery, output_field=models.IntegerField())
).prefetch_related(Prefetch('books', queryset=filtered_books))
for author in authors:
for book in author.books:
if book.price == author.min_book_price:
#cheapest price
if book.price == author.max_book_price:
#most expensive