django中的select_related和prefetch_related性能优化分析

 更新时间:2024年07月17日 14:45:00   作者:半两风  
这篇文章主要介绍了django中的select_related和prefetch_related性能优化分析,本文给大家介绍的非常详细,需要的朋友可以参考下

django中的ORM查询,针对复杂的查询,除了使用A.objects.filter(foreign_name__field)进行查询外。还可以使用select_related 和prefetch_related,进行性能的优化

select_related:

将会根据外键关系(注意: 仅限单对单和单对多关系),在执行查询语句的时候通过创建一条包含SQL inner join操作的SELECT语句来一次性获得主对象及相关对象的信息

1、模型类创建

users/modes.py

from django.db import models
# Create your models here.
class UserInfo(models.Model):
    username = models.CharField(verbose_name='用户名', max_length=225)
    def __str__(self):
        return self.username
    class Meta:
        db_table = 'userinfo'
class Tag(models.Model):
    name = models.CharField(verbose_name='标签名称', max_length=225)
    def __str__(self):
        return self.name
    class Meta:
        db_table = 'tag'
class Article(models.Model):
    title = models.CharField(verbose_name='标题', max_length=225)
    content = models.CharField(verbose_name='内容', max_length=225)
    # 外键
    username = models.ForeignKey(verbose_name='用户', to='UserInfo', on_delete=models.DO_NOTHING)
    tag = models.ManyToManyField(verbose_name='标签', to='Tag')
    def __str__(self):
        return self.title
    class Meta:
        db_table = 'article'

2、添加admin站点,插入测试数据

user/admin.py

from django.contrib import admin
from .models import Article, UserInfo, Tag
# Register your models here.
admin.site.register(UserInfo)
admin.site.register(Article)
admin.site.register(Tag)

3、select_related示例查询

3.1 普通查询

<h1>article列表</h1>
<body>
<ul>
    {% for article in article_queryset %}
        <li>{{ article.title }} <==> {{ article.title }}</li>
    {% endfor %}
</ul>
</body>
def article_list0(request):
    if request.method == 'GET':
        article_queryset = Article.objects.all()
        return render(request, 'user/t1.html', {'article_queryset': article_queryset})

以上可知:只有一次SQL查询记录

3.2 外键查询

<h1>article列表</h1>
<body>
<ul>
    {% for article in article_queryset %}
        <li>{{ article.title }} <==> {{ article.username }}</li>
    {% endfor %}
</ul>
</body>
def article_list(request):
    if request.method == 'GET':
        article_queryset = Article.objects.all()
        return render(request, 'user/t2.html', {'article_queryset': article_queryset})

以上可知:有13次SQL查询

1次查询article表,12次查询article的外键

3.3 性能优化

<h1>article列表</h1>
<body>
<ul>
    {% for article in article_queryset %}
        <li>{{ article.title }} <==> {{ article.username }}</li>
    {% endfor %}
</ul>
</body>
def article_list2(request):
    if request.method == 'GET':
        article_queryset = Article.objects.all().select_related('username')
        # article_queryset = Article.objects.all().prefetch_related()
        return render(request, 'user/t2.html', {'article_queryset': article_queryset})

以上可知:使用select_related进行优化,只有一次SQL查询

3.4 其他示例

# 获取id=1的文章对象同时,获取其相关username信息
Article.objects.select_related('username').get(id=1)
# 获取id=1的文章对象同时,获取其相关作者名字信息
Article.objects.select_related('username__username').get(id=1)
# 获取id=1的文章对象同时,获取其相关tag和相关作者名字信息。下面方法等同。
# 方式一:
Article.objects.select_related('tag', 'username__username').get(id=1)
# 方式二:
Article.objects.select_related('tag').select_related('username__username').get(id=1)
# 使用select_related()可返回所有相关主键信息。all()非必需。
Article.objects.all().select_related()
# 获取Article信息同时获取username信息。filter方法和selected_related方法顺序不重要。
# 方式一:
Article.objects.filter(tag__gt=3).select_related('username')
# 方式二:
Article.objects.select_related('username').filter(tag__gt=3)

4、prefetch_related示例查询

对于多对多字段,你不能使用select_related方法,这样做是为了避免对多对多字段执行JOIN操作从而造成最后的表非常大。

prefetch_related()和select_related()的设计目的很相似,都是为了减少SQL查询的数量,但是实现的方式不一样。后者是通过JOIN语句,在SQL查询内解决问题。但是对于多对多关系,使用SQL语句解决就显得有些不太明智,因为JOIN得到的表将会很长,会导致SQL语句运行时间的增加和内存占用的增加。若有n个对象,每个对象的多对多字段对应Mi条,就会生成Σ(n)Mi 行的结果表。

4.1 普通查询

<h1>{{ tag.name }}</h1>
<body>
<ul>
    {% for article in article_list %}
        <li>{{ article.title }}</li>
    {% endfor %}
</ul>
</body>
def tag_list(request, tid):
    if request.method == 'GET':
        tag = Tag.objects.get(pk=tid)
        article_list = tag.article_set.all()
        return render(request, 'user/t4.html', {'tag': tag, 'article_list': article_list})

4.2 性能优化

<h1>{{ tag.name }}</h1>
<body>
<ul>
    {% for article in tag.article_set.all %}
        <li>{{ article.title }}</li>
    {% endfor %}
</ul>
</body>
def tag_list1(request, tid):
    if request.method == 'GET':
        tag = Tag.objects.prefetch_related('article_set').get(pk=tid)
        return render(request, 'user/t5.html', {'tag': tag})

到此这篇关于django之select_related、prefetch_related的文章就介绍到这了,更多相关django select_related、prefetch_related内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python实现大文本文件分割成多个小文件

    python实现大文本文件分割成多个小文件

    这篇文章主要为大家详细介绍了python实现大文本文件分割成多个小文件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • 解决安装Python的第三方库pandas报错问题

    解决安装Python的第三方库pandas报错问题

    这篇文章主要介绍了解决安装Python的第三方库pandas报错问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Python全栈之学习JS(2)

    Python全栈之学习JS(2)

    这篇文章主要为大家介绍了Python全栈之JS,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • Python结合FastAPI搭建一个接口实现自动生成文档

    Python结合FastAPI搭建一个接口实现自动生成文档

    这篇文章主要为大家详细介绍了Python如何结合FastAPI搭建一个接口,可以实现自动生成文档,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下
    2025-12-12
  • 对numpy中布尔型数组的处理方法详解

    对numpy中布尔型数组的处理方法详解

    下面小编就为大家分享一篇对numpy中布尔型数组的处理方法详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • Python大数据之从网页上爬取数据的方法详解

    Python大数据之从网页上爬取数据的方法详解

    这篇文章主要介绍了Python大数据之从网页上爬取数据的方法,结合实例形式详细分析了Python爬虫爬取网页数据的相关操作技巧,需要的朋友可以参考下
    2019-11-11
  • python仿evething的文件搜索器实例代码

    python仿evething的文件搜索器实例代码

    这篇文章主要介绍了python仿evething的文件搜索器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • Python垃圾回收是怎么实现的

    Python垃圾回收是怎么实现的

    垃圾回收大家应该多多少少都了解过,本文详细的介绍了Python垃圾回收是怎么实现的,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • python实现根据文件关键字进行切分为多个文件的示例

    python实现根据文件关键字进行切分为多个文件的示例

    今天小编就为大家分享一篇python实现根据文件关键字进行切分为多个文件的示例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • Python如何生成随机数及random随机数模块应用

    Python如何生成随机数及random随机数模块应用

    这篇文章主要介绍了Python如何生成随机数及random随机数模块应用,首先我们要知道在python中用于生成随机数的模块是random,在使用前需要import。由此展开内容介绍,需要的小伙伴可以参考一下
    2022-06-06

最新评论