Django实例讲解:用prefect_related解决join操作导致数据膨胀的问题

Admin 2023-01-06 群英技术资讯 441 次浏览

今天小编跟大家讲解下有关“Django实例讲解:用prefect_related解决join操作导致数据膨胀的问题”的内容 ,相信小伙伴们对这个话题应该有所关注吧,小编也收集到了相关资料,希望小伙伴们看了有所帮助。

目录
  • 0. 本文借助django-debug-toolbar来展现效果
  • 1. 介绍
  • 2. 使用
    • 2.1 原生的查询
      • 2.1.1 代码
      • 2.1.2 图示
      • 2.1.3 查询解释 
    • 2.2 使用select_related
      • 2.2.2 代码
      • 2.2.3 图示
      •  2.2.4 解释
      •  2.2.5 其他常用用法
    • 2.3. 使用prefetch_related方法
      • 2.3.1 常用的案例
  • 总结

    0. 本文借助django-debug-toolbar来展现效果

    django-debug-toolbar的安装

    1. 介绍

    select_related:

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

    prefetch_related

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

    Django提供了prefect_related方法来解决这个问题。

    prefect_related可用于多对多关系字段,也可用于反向外键关系(related_name)。

    相同点:

    都作用于queryset对象上面

    注意点:

    • 对与单对单或单对多外键ForeignKey字段,使用select_related方法
    • 对于多对多字段和反向外键关系,使用prefetch_related方法
    • 两种方法均支持双下划线指定需要查询的关联对象的字段名
    • 使用Prefetch方法可以给prefetch_related方法额外添加额外条件和属性。

    2. 使用

    from django.db import models
     
    class UserInfo(models.Model):
        username = models.CharField(verbose_name='用户名', max_length=225)
     
        def __str__(self):
            return self.username
     
    class Tag(models.Model):
        name = models.CharField(verbose_name='标签名称', max_length=225)
     
        def __str__(self):
            return self.name
     
    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

    2.1 原生的查询

    2.1.1 代码

    def article_list(request):
        if request.method == 'GET':
            # select_related---->queryset
            article_queryset = models.Article.objects.all()
            return render(request, 't2.html', context={'article_queryset': article_queryset})

    2.1.2 图示

    2.1.3 查询解释 

    1.从图示我们可以看出来,一共进行13次查询,且有10次重复的!!!

    原因是:当我们第一次查询时,返回的值,只有文章对象,对于标签以及用户,并没有查询,当前端界面需要这两个时,每循环一次,就会去数据库查询一次

    2.为了避免重复查询,django提供select_related和prefetch_related方法来提升数据库查询效率,类似于SQL的JOIN方法。

    3.效果就是当第一次查询时,进行连表,一次性把所有数据全部查询到

    2.2 使用select_related

    2.2.2 代码

    from django.shortcuts import render
     
    from blog import models
     
     
    def article_list(request):
        if request.method == 'GET':
            # select_related---->queryset
            article_queryset = models.Article.objects.all().select_related('tag', 'username')
            return render(request, 't2.html', context={'article_queryset': article_queryset})

    2.2.3 图示

     2.2.4 解释

    可以看到现在只有三次查询,耗时大大减少

     2.2.5 其他常用用法

    # 获取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)

    2.3. 使用prefetch_related方法

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

    2.3.1 常用的案例

    articles = Article.objects.all().select_related('category').prefecth_related('tags')
     
    # 文章列表及每篇文章的tags对象名字信息
    Article.objects.all().prefetch_related('tags__name')
     
    # 获取id=13的文章对象同时,获取其相关tags信息
    Article.objects.prefetch_related('tags').get(id=13)
     
    # 获取文章列表及每篇文章相关的名字以P开头的tags对象信息
    Article.objects.all().prefetch_related(
        Prefetch('tags', queryset=Tag.objects.filter(name__startswith="P"))
    )
     
    # 文章列表及每篇文章的名字以P开头的tags对象信息, 放在article_p_tag列表
    Article.objects.all().prefetch_related(
        Prefetch('tags', queryset=Tag.objects.filter(name__startswith="P")),
    to_attr='article_p_tag'
    )

    本文参考

    Django基础(29): select_related和prefetch_related的用法与区别

    https://www.jb51.net/article/266493.htm

    https://www.jb51.net/article/266498.htm


    以上就是关于“Django实例讲解:用prefect_related解决join操作导致数据膨胀的问题”的相关知识,感谢各位的阅读,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注群英网络,小编每天都会为大家更新不同的知识。
    群英智防CDN,智能加速解决方案

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

    猜你喜欢

    成为群英会员,开启智能安全云计算之旅

    立即注册
    专业资深工程师驻守
    7X24小时快速响应
    一站式无忧技术支持
    免费备案服务
    免费拨打  400-678-4567
    免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
    在线客服
    微信公众号
    返回顶部
    返回顶部 返回顶部
    在线客服
    在线客服