Django ORM调优实践 (2)

要注意的是,在使用QuerySet的时候,一旦在链式操作中改变了数据库请求,之前用prefetch_related缓存的数据将会被忽略掉。这会导致Django重新请求数据库来获得相应的数据,从而造成性能问题。这里提到的改变数据库请求指各种filter()、exclude()等等最终会改变SQL代码的操作。

prefetch_related('comments')隐含表示blog.comments.all(),因此all()并不会改变最终的数据库请求,因此是不会导致重新请求数据库的。

然而

for comment in blog.comments.filter(author="jack"):

就会导致Django重新请求数据库

只需要取出部分字段

博客文章的content字段数据量可能非常大,取出而不用可能会影响性能。之前的需求中可以进一步优化只取出博客和评论中的部分字段

blogs = Blog.objects.filter(name="Django教程").only('id').\ prefetch_related( Prefetch('comments', queryset=Comment.objects.only('id', 'content', 'blog_id')) )

使用only指定查询的字段,使用Prefetch对象自定义prefetch_related查询的内容(默认queryset=Comment.objects.all())

注意comment.blog_id字段是必须要取出的,因为在python中将comments拼到对应的blog时需要comment.blog_id字段与blog.id字段匹配,如果在Prefetch对象中不取出comment.blog_id,拼接时会浪费很多数据库查询去找comment.blog_id字段

多数据库的情况

在多数据库的情况下,prefetch_related使用的数据源与主查询指定的数据源一致。

比如:

blogs = Blog.objects.using('my_db_alias').filter(name="Django教程").only('id').\ prefetch_related( Prefetch('comments', queryset=Comment.objects.only('id', 'content', 'blog_id')) )

查询Comment表时会使用与Blog一样的数据源

五、向数据库插入数据的时候尽量使用bulk_create # 以下代码会发起10次数据库插入: for i in range(10): Comment.objects.create(content=str(i), author="kim", blog_id=1) # 以下代码只会发起一次数据库插入: comments = [] for i in range(10): comments.append(Comment(content=str(i), author="kim", blog_id=1)) Comment.objects.bulk_create(comments, batch_size=5000)

注意:

bulk_create不会返回id:When you bulk insert you don't get the primary keys back

小心数据库连接超时:如果一次性插入过多的数据会导致Mysql has gone away的报错。指定batch_size=5000可以避免这个问题,当插入数据>5000时,会分成多个sql执行数据批量插入

六、尽量不要重复取数据

可以将数据库的数据以id为key存到内存的字典中,这样下次用到的时候就无需再次访问数据库,可提高效率

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppjdz.html