2018.12.25日 【后端开发】新闻详情页ORM性能优化

版权声明:转载记得署名:Dr.Yao https://blog.csdn.net/weixin_42879237/article/details/85255212

外键和表关系

select_related:在提取某个模型的数据的同时,也提前将相关联的数据提取出来。比如提取文章数据,可以使用select_related将author信息提取出来,以后再次使用article.author的时候就不需要再次去访问数据库了。可以减少数据库查询的次数。示例代码如下:

 article = Article.objects.get(pk=1)
 >> article.author # 重新执行一次查询语句
 article = Article.objects.select_related("author").get(pk=2)
 >> article.author # 不需要重新执行查询语句了
select_related只能用在一对多或者一对一中,不能用在多对多或者多对一中。比如可以提前获取文章的作者,但是不能通过作者获取这个作者的文章,或者是通过某篇文章获取这个文章所有的标签。

prefetch_related:这个方法和select_related非常的类似,就是在访问多个表中的数据的时候,减少查询的次数。这个方法是为了解决多对一和多对多的关系的查询问题。比如要获取标题中带有hello字符串的文章以及他的所有标签,示例代码如下:

 from django.db import connection
 articles = Article.objects.prefetch_related("tag_set").filter(title__contains='hello')
 print(articles.query) # 通过这条命令查看在底层的SQL语句
 for article in articles:
     print("title:",article.title)
     print(article.tag_set.all())

 # 通过以下代码可以看出以上代码执行的sql语句
 for sql in connection.queries:
     print(sql)

但是如果在使用article.tag_set的时候,如果又创建了一个新的QuerySet那么会把之前的SQL优化给破坏掉。比如以下代码:

tags = Tag.obejcts.prefetch_related("articles")
 for tag in tags:
     articles = tag.articles.filter(title__contains='hello') #因为filter方法会重新生成一个QuerySet,因此会破坏掉之前的sql优化

 # 通过以下代码,我们可以看到在使用了filter的,他的sql查询会更多,而没有使用filter的,只有两次sql查询
 for sql in connection.queries:
     print(sql)

那如果确实是想要在查询的时候指定过滤条件该如何做呢,这时候我们可以使用django.db.models.Prefetch来实现,Prefetch这个可以提前定义好queryset。示例代码如下:

 tags = Tag.objects.prefetch_related(Prefetch("articles",queryset=Article.objects.filter(title__contains='hello'))).all()
 for tag in tags:
     articles = tag.articles.all()
     for article in articles:
         print(article)

 for sql in connection.queries:
     print('='*30)
     print(sql)

因为使用了Prefetch,即使在查询文章的时候使用了filter,也只会发生两次查询操作。

猜你喜欢

转载自blog.csdn.net/weixin_42879237/article/details/85255212