我是靠谱客的博主 深情电灯胆,最近开发中收集的这篇文章主要介绍django使用数据库ORM时的优化点,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

先放两个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时的优化点所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部