zoukankan      html  css  js  c++  java
  • select_related和prefetch_related的使用

    首选明确一点,这两个都是发生在表连接中,为了避免不必要的数据查询而存在

    创建模型类

    from django.db import models
    
    class Publisher(models.Model):
        name = models.CharField(max_length=300)
    
        def __str__(self):
            return self.name
    
    class Book(models.Model):
        name = models.CharField(max_length=300)
        price = models.IntegerField(default=0)
        publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
    
        class Meta:
            default_related_name = 'books'
    
        def __str__(self):
            return self.name
    
    class Store(models.Model):
        name = models.CharField(max_length=300)
        books = models.ManyToManyField(Book)
    
        class Meta:
            default_related_name = 'stores'
    
        def __str__(self):
            return self.name

    select_related

    • 通过创建连接表的SQL语句进行查询

    使用前:查到book的queryset,然后又到数据库中通过publisher.id查询publish.name,两次进入数据库,效率低

    	queryset = Book.objects.all()
        
        books = []
        for book in queryset:
            books.append({'id': book.id, 'name': book.name, 'publisher': book.publisher.name})
            
        return books

    使用后:在第一次查询时通过SQL语句中使用join将数据预读取,就不用在此查询数据库,效率高

    	queryset = Book.objects.select_related('publisher').all()
    
        books = []
    
        for book in queryset:
            books.append({'id': book.id, 'name': book.name, 'publisher': book.publisher.name})
    
        return books

     

    只能查询多对一或者一对一,也就是对象的外键属性是一个对象如果是一个集合,就需要用到prefetch_related

    prefetch_related

    • 不在数据库中进行连接,而是在python中连接,不创建带join的SQL语句

    使用前:第一次查询得到queryset,然后又对其中每个对象的"外键"属性进行all查询效率低

        queryset = Store.objects.all()
    
        stores = []
    
        for store in queryset:
            books = [book.name for book in store.books.all()]
            stores.append({'id': store.id, 'name': store.name, 'books': books})
    
        return stores

     

    使用后:分别查询每一个表,然后在python语言层面上进行连接,效率比前者高

        queryset = Store.objects.prefetch_related('books')
    
        stores = []
    
        for store in queryset:
            books = [book.name for book in store.books.all()]
            stores.append({'id': store.id, 'name': store.name, 'books': books})
    
        return stores
    • prefetch_related是查询了每个表,然后在语言层面进行连接,而select_related是通过join方法进行数据库的连接,所以select_related在查询的时候是比prefetch_related效率要高的,但是prefetch_related的使用更加广泛,可以进行多对多的查询。
    • 总结:可以理解为外键使用select_related,多对多使用prefetch_related。

    prefetch_related 灵活的使用

        queryset = Store.objects.prefetch_related('books')
    
        stores = []
        for store in queryset:
            books = [book.name for book in store.books.filter(price__range=(250, 300))]
            stores.append({'id': store.id, 'name': store.name, 'books': books})
    
        return stores
    • 如果这样用就会是查询速度变得极其缓慢,比最笨的还慢
    • 分析:
    1. 显示对Store表进行查询,然后对Book查询,得到数据,连接;
    2. 再循环中使用的filter方法过滤了一部分数据,使得连接的数据无法使用
    3. 与最笨的方法比,不仅多查了Book表,还进行了连接,最后连接的数据没有用到,浪费。
    • 解决:在查询Book表之后进行过滤,然后连接,就可以在下面的for循环中使用连接的数据了。
        queryset = Store.objects.prefetch_related(
           Prefetch('books', queryset=Book.objects.filter(price__range=(250, 300))))
    
       stores = []
       for store in queryset:
           books = [book.name for book in store.books.all()]
           stores.append({'id': store.id, 'name': store.name, 'books': books})
    
       return stores

    queryset = Store.objects.prefetch_related( Prefetch('books', queryset=Book.objects.filter(price__range=(250, 300))))

    每天逼着自己写点东西,终有一天会为自己的变化感动的。这是一个潜移默化的过程,每天坚持编编故事,自己不知不觉就会拥有故事人物的特质的。 Explicit is better than implicit.(清楚优于含糊)
  • 相关阅读:
    [2019南昌邀请赛网络赛D][dp]
    [ Educational Codeforces Round 65 (Rated for Div. 2)][二分]
    [hdoj5927][dfs]
    [cf1140D. Minimum Triangulation][dp]
    [hdoj6483][莫队+线段树/ST]
    使用GAC加速 解决CSP问题 Kakuro
    UVA 11427 Expect the Expected
    UVA 11021 Tribles
    UVA 11174 Stand in a Line 树上计数
    《算法概论》第八章的一些课后题目 关于NP-Complete Problem
  • 原文地址:https://www.cnblogs.com/kylin5201314/p/14738195.html
Copyright © 2011-2022 走看看