首页 > 其他分享 >django ORM查询优化

django ORM查询优化

时间:2023-07-10 23:11:52浏览次数:43  
标签:name objects models ORM 查询 book books print django

前言

我们在使用django开发后端接口的时候,经常使用ORM来查询,然后来处理各种各样的数据,下面的一些方法可以提高ORM的查询效率

一、value

创建两张表

class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()
    def __str__(self):
        return self.name

# 书籍表
class Book(models.Model):
    title = models.CharField(max_length=32)
    good = models.IntegerField(default=0)  # 点赞
    comment = models.IntegerField(default=0)  # 评论
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE)

使用all查询

def query(request):
AuthorDetail.objects.create(birthday=datetime.now(),telephone='14513256456',addr='北京')
    books = Book.objects.all()
    for book in books:
        print(book.title,book.publish.name)
    return HttpResponse('ok')

打印结果以及打印的sql

 使用values查询

def query(request):
    books = Book.objects.all().values('title','publish__name')
    print(books)
    return HttpResponse('ok')

打印结果

 

上面通过控制台打印可以看到,输出的sql是不一样的,使用all查询明显是多查询了一次,通过values进行了连表操作,效率就高一些

二、select_related

返回一个QuerySet将“遵循”外键关系的,在执行查询时选择其他相关对象数据。这可以提高性能,从而导致单个更复杂的查询,但意味着以后使用外键关系将不需要数据库查询

简单创建两张表

# 作者表
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    sex = models.CharField(max_length=32, default='male')
    authorDetail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)

    def __str__(self):
        return self.name

# 作者详细信息表
class AuthorDetail(models.Model):
    birthday = models.DateField()  # 出生日期
    telephone = models.CharField(max_length=32)  # 电话
    addr = models.CharField(max_length=64)  # 地址

    def __str__(self):
        return self.addr

以下示例说明了普通查找和select_related()查找之间的区别 。这是标准查询

一对一

def query(request):
    # 查询id 为1的人的手机号
    author = Author.objects.get(id=1)
    print(author.authorDetail.telephone)
    print('*' * 60)
    author = Author.objects.select_related('authorDetail').get(id=1)
    print(author.authorDetail.telephone)
    return HttpResponse('ok')

结果:

使用了select_related之后,里面的参数写的是关系字段的名称,那么就会先进行JOIN语句操作,通过减少SQL查询的次数来进行优化、提高性能,效率高一些,但是他用在外键或者一对一的关系上。 也接受无参数的调用,Django会尽可能深的递归查询所有的字段。但注意有Django递归的限制和性能的浪费

一对多

创建两张表:

# 出版社表
class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name


# 书籍表
class Book(models.Model):
    title = models.CharField(max_length=32)
    good = models.IntegerField(default=0)  # 点赞
    comment = models.IntegerField(default=0)  # 评论
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE)

普通查询

def query(request):
    books = Book.objects.all()
    for book in books:
        print(book.publish.name,book.title)
    return HttpResponse('ok')

结果:

 select_related查询

def query(request):
    books = Book.objects.all().select_related('publish')
    for book in books:
         print(book.publish.name,book.title)
    return HttpResponse('ok')

结果

 小结:
select_related主要针一对一和多对一关系进行优化,产生一次查询,使用SQL的JOIN语句进行优化

三、prefetch_related

这个方法和select_related非常类似,就是在访问多个表中数据的时候,减少查询的次数,这个方法是为了解决多对一和多对多的关系的查询问题

创建两张表

# 书籍表
class Book(models.Model):
    title = models.CharField(max_length=32)
    good = models.IntegerField(default=0)  # 点赞
    comment = models.IntegerField(default=0)  # 评论
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author', through='BookToAuthor')

# 作者表
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    sex = models.CharField(max_length=32, default='male')
    authorDetail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)

使用prefetch_related 查询
查单个书本的作者:

def query(request):
    books = Book.objects.get(id=1)
    print(books.authors.all())
    print('*' * 50)
    books = Book.objects.prefetch_related('authors').get(id=1)
    print(books.authors.all())
    return HttpResponse('ok')

查所有书本的作者

def query(request):
    books = Book.objects.all()
    for book in books:
        for author in book.authors.all():
            print(author.name)
    print('*' * 50)
    books = Book.objects.prefetch_related('authors','publish').all()
    for book in books:
        for author in book.authors.all():
            print(author.name)
    return HttpResponse('ok')

 后面还可以跟过滤条件:

def query(request):
    books = Book.objects.prefetch_related('authors').filter(authors__age=12)
    for book in books:
        print(book.title)
    return HttpResponse('ok')

 所有书的出版社

def query(request):
    books = Book.objects.prefetch_related('publish')
    for book in books:
        print(book.publish.name)
    return HttpResponse('ok')

注意事项:
在预查询数据中使用filter?

def query(request):
    books = Book.objects.prefetch_related('authors')
    for book in books:
        for author in book.authors.filter(age__gte=10):
            print(author.name)
    return HttpResponse('ok')

看下结果,可以看到产生了多次查询,这肯定是有问题,如果使用了filter,会把之前的预加载给清除掉重新向数据库发送请求,可以使用Prefetch来过滤需要操作的条件:

 Prefetch:

from django.db.models import Prefetch
def query(request):
    books = Book.objects.prefetch_related(
    Prefetch('authors',queryset=Author.objects.filter(age__gte=10)))
    for book in books:
        for author in book.authors.all():
            print(author.name)
    return HttpResponse('ok')

结果

 

四、only和defer

only:只提取某几个字段

def query(request):
    author = Author.objects.all().only('name') # 只提取name字段
    print(author)
    return HttpResponse('ok')

sql

 注意:如果后面你再提取其他字段则会发起数据库请求。id无法操作,下同defer

defer:过滤字段

def query(request):
    author = Author.objects.all().defer('name','age')
    print(author)
    return HttpResponse('ok')

sql

 注意:如果你将字段过滤掉但后续又操作这个字段的话会再次发起数据库请求

 

参考博客:

https://blog.csdn.net/qq_39253370/article/details/108443148

https://blog.csdn.net/PY0312/article/details/103301693

标签:name,objects,models,ORM,查询,book,books,print,django
From: https://www.cnblogs.com/Durant0420/p/17542624.html

相关文章

  • python: sqlalchemy ORM in mysql
     """StudengMaping.pyORM(ObjectRelationalMapping)学生表实体类对象关系映射one-oneone-moremore-onemore-moredate2023-06-23edit:GeovinDu,geovindu,涂聚文ide:PyCharm2023.1python11sqlalchemy2.0.1.6https://docs.sqlalchemy.org/en/20/cor......
  • Django 在终端打印 ORM 对应的 SQL 语句的两种方式
    前言在使用Django框架开发项目中,如果想知道使用ORM语句操作数据库转换对应的SQL语句时,那么可以使用两种方式来实现方法一在 Django 项目的 settings.py 文件中,找到日志配置LOGGING,没有找到日志配置项的直接复制粘贴如下代码即可配置好之后,重新运行项目,再执行任何对......
  • WPF应用中对WindowsFormHost内容进行裁剪
    问题1:  WPF中在使用WindowsFormsHost调用WinFrom控件时,若在WindowsFormsHost上层添加了WPF控件,该控件不会显示出来。<Grid><WindowsFormsHostBackground="White"><Winfrm:WebBrowserx:Name="WinFrmWebBrowser"/></WindowsFormsHo......
  • xtrabackup 恢复报错:Assertion failure: log0files_finder.cc:322:format >= Log_form
     2023-07-10T15:33:46.614144+08:000[Note][MY-012204][InnoDB]Scanning'./'2023-07-10T15:33:46.647712+08:000[Note][MY-012208][InnoDB]CompletedspaceIDcheckof229files.2023-07-10T15:33:46.648265+08:000[Note][MY-012955][InnoDB]Ini......
  • MySQL---索引优化与查询优化
     索引失效案例全值匹配我最爱当where条件的所有字段都有索引完全匹配时,效率最高最左前缀规则(联合索引)联合索引,在检索数据时从联合索引的最左侧开始匹配主键插入顺序计算/函数/类型转换(自动或手动)导致索引失效......
  • Element el-form 根据选择条件动态控制表单必填项
    Html:<el-form-itemlabel="审核意见"prop="remark":rules="recordForm.status=='10'?rules.remark:[{required:false}]"><el-inputtype="textarea"v-model="recordForm.remark">......
  • union和子查询中order by一起使用导致排序失效问题及解决
    转:https://www.jb51.net/article/271119.htmmysql版本:5.7Union的时候,如果子查询中有orderby可能到导致子查询的排序结果不符合预期原因:    可能是union和被msyql优化器优化导致的排序失效解决方法:    可以在子查询后面加上limit一个肯定大于查询数据量的数......
  • 接上篇:如何在项目中实现ES查询功能?
     大家好,之前我们教大家如何将MySQL数据同步到ES。这篇文章在技术派项目中实现ES查询功能。不多说上文章目录: 01背景在SpringBoot整合ES中,有两种常见方法,一种是ElasticsearchRestTemplate,另一种是RestHighLevelClient。ElasticsearchRestTemplate是ES基......
  • 使用CRM REST Builder的Predefined Query在js结合FetchXML语句进行查询
    一般情况下使用拓展工具RESTBuilder编辑器,可以很方便的进行操作js中增删改查均能实现,但在某些较为特殊的场景下,需要根据条件去拼接查询过滤条件的,使用编辑器生成的代码无法实现,需要结合使用fetchXML,比如某个条件多个值都查询需要使用in查询,再或者需要过滤关联表中的某个字段的值。......
  • 007 学习笔记--约束 + 多表查询
    约束:是作用于表中字段上的规则,用于限制存储在标中的数据;其目的,是保证数据库中的数据的正确、有效和完整性;约束分类:--约束createtableifnotexistsusers( idintPRIMARYkeyauto_incrementCOMMENT'主键', nameVARCHAR(100)notnulluniqueCOMMENT'姓名',--......