Django数据库操作性能相关

Django数据库操作性能相关

案例:

现在我们的数据库中有两张表如下:

1.职员表:

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=64)
    ut = models.ForeignKey(to='UserType',to_field='id',null=True)

2.职位表:

class UserType(models.Model):
    Job = models.CharField(max_length=32)

需求:

1.我们现在将所有的职员和对应的职位输入出来:

def login(request):

    user_list = models.UserInfo.objects.all()
    
	for row in user_list:
        print(row.name,row.pwd,row.ut.Job)  


    return HttpResponse("OK")

上述代码中row.name和row.pwd是单表操作而row.ut.job关系到了连表操作。当代码执行到for循环时下面每一次循环都经过了一次数据库,即带着ForeignKey的ut去UserType表中读取职位信息,过程中循环5次就进入数据库5次,所以随着数据库的数据的增加其性能会越来越低。

所以我们需要优化:

优化代码:

def login(request):

   
    user_list2=models.UserInfo.objects.values("name","pwd","ut__Job")
    print(user_list2.query)

    print(user_list.query)
    for row in user_list2:
        print(row["name"],row["pwd"],row["ut__Job"])


    return HttpResponse("OK")

通过values可以一次性将两张表得数据都取出来在通过for循环输出对应的数据,该过程只查询一次数据库,性能比之前强很多。

但是values的取值方式只是values值,更多的时候我们需要的是一个个的对象,所以下面我们可以使用这种方式:

def login(request):

    user_list = models.UserInfo.objects.all().select_related('ut')  #该处的"ut"是该表的ForeignKey的字段。

    print(user_list.query)  #查看MySQL查询语句

这是MySQL的原生查询语句:

SELECT "xingneng_userinfo"."id", "xingneng_userinfo"."name", "xingneng_userinfo"."pwd", "xingneng_userinfo"."ut_id", "xingneng_usertype"."id", "xingneng_usertype"."Job" FROM "xingneng_userinfo" LEFT OUTER JOIN "xingneng_usertype" ON ("xingneng_userinfo"."ut_id" = "xingneng_usertype"."id")

综上所述的查询我们统称为主动连表查询,其缺点就性能低

	select_related,主动连表查询【FK】
		
		user_list = models.UserInfo.objects.all().select_related('FK字段')
		for row in user_list:
			# 只去取当前表数据和FK表关联字段
	
	
		user_list = models.UserInfo.objects.values(...)
		for row in user_list:
			# 只去取当前表数据和FK表关联字段

prefetch_related方法

def login(request):

    user_list = models.UserInfo.objects.all().prefetch_related('ut')

    
    for row in user_list:
        print(row.name,row.pwd,row.ut.Job)
    return HttpResponse("OK")

上述的代码整个执行流程:

  • 查询职员表models.UserInfo.objects.all

  • 把用户表中所有的ut_id拿到,用户类型ID[1,2,3]

  • select * from UserType where id in [1,2,3]

这里需要理解的是当职员表中用1000个职员,但是职位类型却只有三种[1,2,3],那么prefetch_related方法就只会将这三个类型的职位读取出来而不会去循环一千次取一千次。这里没有练表而且只分别去两个表中读取对应的数据,即只执行两次数据库查询。

only方法(只取某个字段)

def login(request):

    user_list = models.UserInfo.objects.all().only('name')


    for row in user_list:
        print(row.name)
    return HttpResponse("OK")

only后的字段表示在查询数据库时只查该字段,且该字段的查询结果也是一个个的对象,相比values更优些。需要注意当你查询的字段不是only中的字段其性能会很差

defer方法(排除某个字段)

def login(request):

    user_list = models.UserInfo.objects.all().defer('name')


    for row in user_list:
        print(row.pwd)
    return HttpResponse("OK")

defer方法刚好与only方法相反,表示只查与defer后的字段以外的字段。需要注意当你查询的字段是你排除的字段,查询的性能会很低

原文地址:https://www.cnblogs.com/lijian-22huxiaoshan/p/7647288.html