select_related和prefetch_related
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了select_related和prefetch_related相关的知识,希望对你有一定的参考价值。
select_related
1)通过filter或values进行跨表查询
book_queryset=models.Book.objects.filter(title=‘西游记‘).values(‘publish__pk‘,‘publish__name‘,‘pk‘,‘title‘,‘price‘)
print(book_queryset)
<QuerySet [{‘publish__pk‘: 2, ‘publish__name‘: ‘人名出版社‘, ‘pk‘: 5, ‘title‘: ‘西游记‘, ‘price‘: Decimal(‘345.67‘)}]>
SELECT app01_book.publish_id, app01_publish.name, app01_book.nid, app01_book.title, app01_book.price FROM "app01_book" INNER JOIN "app01_publish" ON app01_book.publish_id = app01_publish.nid WHERE app01_book.title = ‘西游记‘ LIMIT 21;
2)分步查询,访问数据库两次
book_queryset=models.Book.objects.filter(title="西游记")
print(book_queryset)
author_queryset=book_queryset.values(‘publish__pk‘,‘publish__name‘,‘pk‘,‘title‘,‘price‘)
print(author_queryset)
<QuerySet [<Book: Book object>]>
<QuerySet [{‘publish__pk‘: 2, ‘publish__name‘: ‘人名出版社‘, ‘pk‘: 5, ‘title‘: ‘西游记‘, ‘price‘: Decimal(‘345.67‘)}]>
SELECT "app01_book"."nid", "app01_book"."title", "app01_book"."publishDate", "app01_book"."price", "app01_book"."keepNum"
, "app01_book"."commentNum", "app01_book"."publish_id" FROM "app01_book" WHERE app01_book.title = ‘西游记‘ LIMIT 21; SELECT app01_book.publish_id, app01_publish.name, app01_book.nid, app01_book.title, app01_book.price FROM "app01_book" INNER JOIN "app01_publish" ON app01_book.publish_id = app01_publish.nid WHERE app01_book.title = ‘西游记‘ LIMIT 21;
3)使用select_related,跨表查询,查询一次
book_queryset=models.Book.objects.select_related().filter(title="西游记") print(book_queryset) publish_queryset=book_queryset.values(‘publish__pk‘,‘publish__name‘,‘pk‘,‘title‘,‘price‘) print(publish_queryset) <QuerySet [<Book: Book object>]> <QuerySet [{‘publish__pk‘: 2, ‘publish__name‘: ‘人名出版社‘, ‘pk‘: 5, ‘title‘: ‘西游记‘, ‘price‘: Decimal(‘345.67‘)}]>
SELECT app01_book.nid, app01_book.title, app01_book.publishDate, app01_book.price, app01_book.keepNum , app01_book.commentNum, app01_book.publish_id, app01_publish.nid, app01_publish.name, app01_publish.city , app01_publish.email FROM "app01_book" INNER JOIN "app01_publish" ON app01_book.publish_id = app01_publish.nid WHERE app01_book.title = ‘西游记‘ LIMIT 21; SELECT app01_book.publish_id, app01_publish.name, app01_book.nid, app01_book.title, app01_book.price FROM "app01_book" INNER JOIN "app01_publish" ON app01_book.publish_id = app01_publish.nid WHERE app01_book.title = ‘西游记‘ LIMIT 21;
# Hits the database. e = Entry.objects.get(id=5) # Hits the database again to get the related Blog object. b = e.blog
# Hits the database. e = Entry.objects.select_related(‘blog‘).get(id=5) # Doesn‘t hit the database, because e.blog has been prepopulated # in the previous query. b = e.blog
from django.utils import timezone # Find all the blogs with entries scheduled to be published in the future. blogs = set() for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related(‘blog‘): # Without select_related(), this would make a database query for each # loop iteration in order to fetch the related blog for each entry. blogs.add(e.blog)
Entry.objects.filter(pub_date__gt=timezone.now()).select_related(‘blog‘) Entry.objects.select_related(‘blog‘).filter(pub_date__gt=timezone.now())
from django.db import models class City(models.Model): # ... pass class Person(models.Model): # ... hometown = models.ForeignKey( City, on_delete=models.SET_NULL, blank=True, null=True, ) class Book(models.Model): # ... author = models.ForeignKey(Person, on_delete=models.CASCADE)
b = Book.objects.select_related(‘author__hometown‘).get(id=4) p = b.author # Doesn‘t hit the database. c = p.hometown # Doesn‘t hit the database. b = Book.objects.get(id=4) # No select_related() in this example. p = b.author # Hits the database. c = p.hometown # Hits the database.
prefetch_related
from django.db import models class Topping(models.Model): name = models.CharField(max_length=30) class Pizza(models.Model): name = models.CharField(max_length=50) toppings = models.ManyToManyField(Topping) def __str__(self): # __unicode__ on Python 2 return "%s (%s)" % ( self.name, ", ".join(topping.name for topping in self.toppings.all()), )
1) 不使用prefetch_related, 共进行四次查询
pizza_queryset=models.Pizza.objects.all() print(pizza_queryset)
<QuerySet [<Pizza: alex (tomato, capsicum, eggplant, zucchini, mushrooms)>, <Pizza: egon (tomato, capsicum, eggplant, zucchini, mushrooms)>, <Pizza: yuan (tomato, capsicum, eggplant, zucchini)>]>
SELECT app01_pizza.id, app01_pizza.name FROM "app01_pizza" LIMIT 21; SELECT app01_topping.id, app01_topping.name FROM "app01_topping" INNER JOIN "app01_pizza_toppings" ON app01_topping.id = app01_pizza_toppings.topping_id WHERE app01_pizza_toppings.pizza_id = 1; SELECT app01_topping.id, app01_topping.name FROM "app01_topping" INNER JOIN "app01_pizza_toppings" ON app01_topping.id = app01_pizza_toppings.topping_id WHERE app01_pizza_toppings.pizza_id = 2; SELECT app01_topping.id, app01_topping.name FROM "app01_topping" INNER JOIN "app01_pizza_toppings" ON app01_topping.id = app01_pizza_toppings.topping_id WHERE app01_pizza_toppings.pizza_id = 3;
2) 使用prefetch_related, 共进行两次次查询
pizza_queryset=models.Pizza.objects.all().prefetch_related(‘toppings‘)
print(pizza_queryset)
<QuerySet [<Pizza: alex (tomato, capsicum, eggplant, zucchini, mushrooms)>, <Pizza: egon (tomato, capsicum, eggplant, zucchini, mushrooms)>, <Pizza: yuan (tomato, capsicum, eggplant, zucchini)>]>
SELECT app01_pizza.id, app01_pizza.name FROM "app01_pizza" LIMIT 21; SELECT app01_pizza_toppings.pizza_id AS "_prefetch_related_val_pizza_id", app01_topping.id, app01_topping.name FROM "app01_topping" INNER JOIN "app01_pizza_toppings" ON app01_topping.id = app01_pizza_toppings.topping_id WHERE app01_pizza_toppings.pizza_id IN (1, 2, 3);
参考:https://docs.djangoproject.com/en/1.11/ref/models/querysets/#django.db.models.query.QuerySet.prefetch_related
以上是关于select_related和prefetch_related的主要内容,如果未能解决你的问题,请参考以下文章
Django:select_related() 的用法和执行时间性能
如何结合 select_related() 和 value()? (2016)
Django查询优化之select_related和prefetch_related