Django ORM效率提升技巧

1.QuerySet原理

日常django中使用的filter查询是返回QuerySet对象,是懒加载,只有当访问到对应数据的时候,才会真正访问数据库,如果再次访问查询到的数据,将不会触发数据查询。
例子:

queryset = KeyWord.objects.all()

# 访问数据,执行数据查询
if queryset:
    print("123")

# 再次读取数据,不会执行数据查询
first_data = queryset[0]

2.select_related查询(连表查询)

性能相关:表之间进行join连表操作,一次性获取关联的数据。适用于多对一

在Model存在外键的情况下,进行关联查询,如果使用正常的“.外键”的方式,会出现重复查询的情况,为了提高效率,可以使用select_related方法查询外键,本质是通过sql中的join来进行连接查询

总结:

  1. select_related主要针一对一和多对一关系进行优化。
  2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
    3.prefetch_related是通过再执行一条额外的SQL语句,然后用 Python 把两次SQL查询的内容关联(joining)到一起
    Model
Class Blog(models.Model):
    title = models.CharField(max_length=32)
    description = models.CharField(max_length=255)
    author = models.ForeignKey(Author)

Class Author(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField(unique=True)
    city = models.CharField(max_length=32)

不好的查询事例

# 访问一次数据库
blog = Blog.objects.get(id=124)

# 再次访问数据库
author = blog.author

使用select_related查询

# 访问数据库
blog = Blog.objects.select_related('author').get(id=124)

# 这里不会再次访问数据库,在之前的查询中已经取到了对应的数据
author = blog.author

3.prefetch_related查询(多次查询)使用一对多,多对多

性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。

总结:

  1. 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。
  2. prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。
q = models.UserInfo.objects.all().prefetch_related('fk_ug')
for row in q:
    print(row.id, row.fk_ug.title)

可以看出上述语句实现了跨表,但并没有连表查询,而是使用多次查询,

首先,select * from UserInfo并统计fk_ug的种类

然后通过select * from usertype where id in [2, 4]得到usertype,然后得到最终的数据。

通过这种方式,在数据量比较大的情况下,相比于连表提高了查询效率。

4.判断数据是否存在最佳实践

# 好的示例
exists = Blog.objects.filter(category='django').exists()

#不好的示例

blogs = Blog.objects.filter(category='django')  
exists = len(blogs)>0

exists = Blog.objects.filter(category='django').count() > 0

5.获取数据的数量

# Bad query
blogs = Blog.objects.filter(category='django')  
count = len(blogs)

# Good Query 最佳实践
count = Blog.objects.filter(category='django').count()

6.直接使用外键

在需要到外键id时,最好直接使用属性_id的参数,直接获取外键id值。

# Bad query, additional db lookup in author table
blog = Blog.objects.get(id=2)
author_id = blog.author.id  

# A better version of above query but still a bad query
blog = Blog.objects.select_related('author').get(id=2)
author_id = blog.author.id  

# Good Query 最佳实践
blog = Blog.objects.get(id=2)
author_id = blog.author_id

7.减少字段返回

queryset.values()

以字段形式返回数据

queryset.values_list()

以列表嵌套元组的方式返回数据

only

只查询指定列

# Good Query 最佳实践,只查询 Blog 的 title 与 author
blogs = Blog.objects.filter(category='django').only('author','title').select_related('author')

difer

查询除了指定列之外的其他列

# Good Query 最佳实践,查询除了 description 外 Blog 的其他字段值
blogs = Blog.objects.filter(category='django').defer('description').select_related('author')

8.在Python脚本中调用Django环境

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()

    from app01 import models

    books = models.Book.objects.all()
    print(books)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值