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.(清楚优于含糊)
  • 相关阅读:
    素数路径Prime Path POJ3126 素数,BFS
    Fliptile POJ3279 DFS
    Find the Multiple POJ1426
    洗牌Shuffle'm Up POJ3087 模拟
    棋盘问题 POJ1321 DFS
    抓住那只牛!Catch That Cow POJ3278 BFS
    Dungeon Master POJ2251 三维BFS
    Splitting into digits CodeForce#1104A
    Ubuntu下手动安装Nvidia显卡驱动
    最大连续子序列和
  • 原文地址:https://www.cnblogs.com/kylin5201314/p/14738195.html
Copyright © 2011-2022 走看看