概述
先放两个model方便说明
from django.db import models
from django.contrib.auth.models import AbstractUser, UnicodeUsernameValidator
class User(AbstractUser):
username_validator = UnicodeUsernameValidator()
user_id = models.CharField('用户ID', primary_key=True, max_length=11, default='')
username = models.CharField('用户名', max_length=20, unique=True, default='', validators=[username_validator])
password = models.CharField('密码', max_length=128, default='')
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
class Address(models.Model):
user = models.OneToOneField(User, models.CASCADE, verbose_name='用户', primary_key=True, max_length=11, default='')
phone = models.CharField('收件电话', max_length=14, default='')
address = models.CharField('收件地址', max_length=50, default='')
1. 使用select_related进行关联查询
查询时如果要查询地址对应的用户信息,使用select_related进行关联查询,多个表的信息一次就查询完毕了,否则会进行多次查询。
下面的方法会进行两次查询:
address = Address.objects.filter(phone=phone).first()
username = address.user.username
# 或者
address = Address.objects.filter(phone=phone).first()
user = User.objects.filter(user_id=address.user_id).first()
username = user.username
下面的方法会进行一次查询:
address = Address.objects.filter(phone=phone).select_related('user').first()
username = address.user.username
另外如果是三个表关联,这样进行关联查询:
# company是用户所属的公司
address = Address.objects.filter(phone=phone).select_related('user__company').first()
company_name = address.user.company.company_name
2. 指定values
查询时指定要查的值,可以减少传输的数据量,比如我们只需要地址的地址信息,应该这样做
address = Address.objects.filter(phone=phone).values('address')
address = address[0]['address']
3. 少用all(),多用all()[*: *]
如果数据量很大,最好把一次查询拆分为多次。使用all()[*: *]会在sql中增加limit,进行切片查询后可以加快查询速度 ,防止一次查询所有数据导致数据库拥堵。在第一个切片的查询完毕我们就可以使用并发开始处理数据,而不需要等所有数据查询完毕,这样可以提高处理数据的效率。
4. 取值用first(),判断是否存在用exist()
如果仅仅需要确定数据是否存在,使用exist(),django中对exist单独做了优化。
使用first()时的sql是:
select user.user_id, user.username, ... from user where ...;
使用exist()时的sql是:
select count(1) from user where ...;
熟悉SQL优化的开发者都知道后者的查询速度高于前者。
5. 对user.address_set进行重定义
有时我们需要进行反向关联查询,比如查询某用户的所有收件地址,django提供了user.address_set这样的方式,但是查询多个用户的地址信息时,不推荐使用这种方式。
原来的方式进行多次查询:
users = User.objects.all()
addresses = []
for user in users:
addresses.extend(user.address_set.all())
改进的方式两次查询:
users = User.objects.values('user_id')
user_ids = [user['user_id'] for user in users]
addresses = Address.objects.filter(user_id_in=user_ids).all()
6. 插入主键而不是对象
Address(user_id=user_id, phone='', address='').save()
优于
user = User.objects.filter(user_id=user_id).first()
Address(user=user, phone='', address='').save()
7. QuerySet进行or查询的方法
from django.db.models import Q
users = User.objects.filter(Q(username=name_a) | Q(username=name_b)).all()
8. 更新时指定字段
# update user set username='...' where username='...';
update_count = User.objects.filter(username=username).update(username=username + 'new') # 无论单个更新还是批量更新都尽量使用这种方法
单个更新时等于,批量更新时优于
user = User.objects.filter(username=username).first()
user.username = username + 'new'
# update user set username='...' where username='...';
user.save(update_fields=['username']) # 指定要更新的字段,效率高
优于
user = User.objects.filter(username=username).first()
user.username = username + 'new'
# update user set user_id=..., username='...', password='...' where username='...';
user.save() # 会更新所有字段,效率低
最后
以上就是深情电灯胆为你收集整理的django使用数据库ORM时的优化点的全部内容,希望文章能够帮你解决django使用数据库ORM时的优化点所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复