1. 程式人生 > 實用技巧 >飲冰三年-人工智慧-Python-48 Django ORM 效能優化

飲冰三年-人工智慧-Python-48 Django ORM 效能優化

這是飲冰三年-人工智慧-Python-24 Django ORM增刪改查的進階篇

一、準備

1:搭建好django環境,通過模型生成資料庫,

from django.db import models

class Book(models.Model):
    name=models.CharField(max_length=20)
    price = models.IntegerField()
    pub_date=models.DateField()
    # 建立一對多的方法
    publish = models.ForeignKey("Publish",on_delete=models.CASCADE)
    
# 建立多對多的方法 authors=models.ManyToManyField("Author") class Publish(models.Model): name = models.CharField(max_length=32) city = models.CharField(max_length=32) class Author(models.Model): name=models.CharField(max_length=32) age=models.IntegerField()
imodels.py

2:初始化資料庫

delete from
app01_publish where 1=1; update sqlite_sequence set seq=0 where name='app01_publish'; insert into app01_publish(name,city)values ('清華大學出版社','北京'); insert into app01_publish(name,city)values ('北京大學出版社','北京'); insert into app01_publish(name,city)values ('上海商務出版社','上海'); select * from app01_publish; delete
from app01_book where 1=1; update sqlite_sequence set seq=0 where name='app01_book'; insert into app01_book (name,price,pub_date,publish_id)values ('天龍八部',200,'2000-01-01',3); insert into app01_book (name,price,pub_date,publish_id)values ('神鵰俠侶',150,'2011-01-01',3); insert into app01_book (name,price,pub_date,publish_id)values ('Python入門',100,'2020-01-01',1); insert into app01_book (name,price,pub_date,publish_id)values ('Python精通',90,'2022-01-01',1); select * from app01_book; delete from app01_author where 1=1; update sqlite_sequence set seq=0 where name='app01_author'; insert into app01_author (name,age)values ('金庸',93); insert into app01_author (name,age)values ('倪匡',83); insert into app01_author (name,age)values ('武沛齊',83); insert into app01_author (name,age)values ('袁浩',83); select * from app01_author; delete from app01_book_authors where 1=1; update sqlite_sequence set seq=0 where name='app01_book_authors'; --《天龍八部》作者:金庸、倪匡 --《神鵰俠侶》作者:金庸、 --《Python入門》作者:武沛齊、 --《Python精通》作者:袁浩、武沛齊 insert into app01_book_authors (book_id,author_id)values (1,1); insert into app01_book_authors (book_id,author_id)values (1,2); insert into app01_book_authors (book_id,author_id)values (2,1); insert into app01_book_authors (book_id,author_id)values (3,3); insert into app01_book_authors (book_id,author_id)values (4,3); insert into app01_book_authors (book_id,author_id)values (4,4); select * from app01_book_authors;
初始化資料

3:設定資料庫日誌記錄

二、select_related()

對於一對一欄位(OneToOneField)和外來鍵欄位(ForeignKey),可以使用select_related 來對QuerySet進行優化

場景一:獲取每本書的名稱和出版社

def getbook_publish():
    '''獲取=書籍的出版社'''
    books = Book.objects.all()
    for book in books:
        print(book.name, book.publish.name)
[2020-07-26 17:01:39,484] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book"; args=()
[2020-07-26 17:01:39,485] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish" WHERE "app01_publish"."id" = 3 LIMIT 21; args=(3,)
天龍八部 上海商務出版社
[2020-07-26 17:01:39,486] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish" WHERE "app01_publish"."id" = 3 LIMIT 21; args=(3,)
神鵰俠侶 上海商務出版社
[2020-07-26 17:01:39,486] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish" WHERE "app01_publish"."id" = 1 LIMIT 21; args=(1,)
Python入門 清華大學出版社
[2020-07-26 17:01:39,487] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish" WHERE "app01_publish"."id" = 1 LIMIT 21; args=(1,)
Python精通 清華大學出版社
輸出結果

優化後

def getbook_publish2():
    '''獲取=書籍的出版社'''
    books = Book.objects.select_related("publish").all()
    for book in books:
        print(book.name, book.publish.name)


getbook_publish2()
[2020-07-26 17:35:50,650] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id", "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_book" INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id"); args=()
天龍八部 上海商務出版社
神鵰俠侶 上海商務出版社
Python入門 清華大學出版社
Python精通 清華大學出版社
輸出結果

二、prefetch_related()

對於多對多欄位(ManyToManyField)和一對多欄位,可以使用prefetch_related()來進行優化。

場景一:獲取每個出版社出版的書(一對多)

def get_publish_book():
    '''獲取每個出版社出版的資料名稱(效能較差)'''
    publishs = Publish.objects.all()
    for publish in publishs:
        for book in publish.book_set.all():
            print(publish.name, book.name)


get_publish_book()
View Code
'''
[2020-07-27 19:31:59,218] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish"; args=()
[2020-07-27 19:31:59,220] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" WHERE "app01_book"."publish_id" = 1; args=(1,)
清華大學出版社 Python入門
清華大學出版社 Python精通
[2020-07-27 19:31:59,221] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" WHERE "app01_book"."publish_id" = 2; args=(2,)
[2020-07-27 19:31:59,222] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" WHERE "app01_book"."publish_id" = 3; args=(3,)
上海商務出版社 天龍八部
上海商務出版社 神鵰俠侶
'''
輸出結果

優化後

def get_publish_book2():
    '''獲取每個出版社出版的資料名稱(效能較好)'''
    publishs = Publish.objects.prefetch_related('book_set')
    for publish in publishs:
        for book in publish.book_set.all():
            print(publish.name, book.name)


get_publish_book2()
view code
'''
[2020-07-27 19:39:39,342] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish"; args=()
[2020-07-27 19:39:39,343] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" WHERE "app01_book"."publish_id" IN (1, 2, 3); args=(1, 2, 3)
清華大學出版社 Python入門
清華大學出版社 Python精通
上海商務出版社 天龍八部
上海商務出版社 神鵰俠侶
'''
輸出結果

場景二:獲取每個出版社出版的書(多對多)

def get_author_book():
    '''獲取每個作者出版的書(效能較差)'''
    authors = Author.objects.all()
    for author in authors:
        for book in author.book_set.all():
            print(author.name, book.name)


get_author_book()
View Code
'''
[2020-07-27 19:53:17,837] (0.000) SELECT "app01_author"."id", "app01_author"."name", "app01_author"."age" FROM "app01_author"; args=()
[2020-07-27 19:53:17,838] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") WHERE "app01_book_authors"."author_id" = 1; args=(1,)
金庸 天龍八部
金庸 神鵰俠侶
[2020-07-27 19:53:17,839] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") WHERE "app01_book_authors"."author_id" = 2; args=(2,)
倪匡 天龍八部
[2020-07-27 19:53:17,840] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") WHERE "app01_book_authors"."author_id" = 3; args=(3,)
武沛齊 Python入門
武沛齊 Python精通
[2020-07-27 19:53:17,840] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") WHERE "app01_book_authors"."author_id" = 4; args=(4,)
袁浩 Python精通
'''
輸出結果
def get_author_book2():
    '''獲取每個作者出版的書(效能較好)'''
    authors = Author.objects.prefetch_related('book_set')
    for author in authors:
        for book in author.book_set.all():
            print(author.name, book.name)


get_author_book2()
View Code
'''
[2020-07-27 19:52:09,036] (0.000) SELECT "app01_author"."id", "app01_author"."name", "app01_author"."age" FROM "app01_author"; args=()
[2020-07-27 19:52:09,038] (0.000) SELECT ("app01_book_authors"."author_id") AS "_prefetch_related_val_author_id", "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") WHERE "app01_book_authors"."author_id" IN (1, 2, 3, 4); args=(1, 2, 3, 4)
金庸 天龍八部
金庸 神鵰俠侶
倪匡 天龍八部
武沛齊 Python入門
武沛齊 Python精通
袁浩 Python精通
'''
輸出結果

三、prefetch_related()和select_related()

場景一:獲取每個作者合作的出版社

def get_author_publish():
    '''獲取每個作者合作的出版社(效能較差)'''
    authors = Author.objects.all()
    for author in authors:
        for book in author.book_set.all():
            print(author.name, book.name, book.publish.name)


get_author_publish()
View Code
'''
[2020-07-27 20:10:40,919] (0.000) SELECT "app01_author"."id", "app01_author"."name", "app01_author"."age" FROM "app01_author"; args=()
[2020-07-27 20:10:40,920] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" 
                                  FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id")
                                  WHERE "app01_book_authors"."author_id" = 1; args=(1,)
[2020-07-27 20:10:40,921] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish" WHERE "app01_publish"."id" = 3 LIMIT 21; args=(3,)
金庸 天龍八部 上海商務出版社
[2020-07-27 20:10:40,922] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish" WHERE "app01_publish"."id" = 2 LIMIT 21; args=(2,)
金庸 神鵰俠侶 北京大學出版社
[2020-07-27 20:10:40,922] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" 
                                  FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") 
                                  WHERE "app01_book_authors"."author_id" = 2; args=(2,)
[2020-07-27 20:10:40,923] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish" WHERE "app01_publish"."id" = 3 LIMIT 21; args=(3,)
倪匡 天龍八部 上海商務出版社
[2020-07-27 20:10:40,924] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" 
                                  FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") 
                                  WHERE "app01_book_authors"."author_id" = 3; args=(3,)
                                  
[2020-07-27 20:10:40,925] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" 
                                  FROM "app01_publish" WHERE "app01_publish"."id" = 1 LIMIT 21; args=(1,)
武沛齊 Python入門 清華大學出版社
[2020-07-27 20:10:40,925] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" 
                                  FROM "app01_publish" WHERE "app01_publish"."id" = 1 LIMIT 21; args=(1,)
武沛齊 Python精通 清華大學出版社
[2020-07-27 20:10:40,926] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" 
                                  FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") 
                                  WHERE "app01_book_authors"."author_id" = 4; args=(4,)
[2020-07-27 20:10:40,927] (0.000) SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_publish" WHERE "app01_publish"."id" = 1 LIMIT 21; args=(1,)
袁浩 Python精通 清華大學出版社
ps:
    1:先根據作者表和書籍表的關係拿到,該作者撰寫的所有出版社id,迴圈這些書籍對應的出版社id    
'''
輸出結果

優化後

def get_author_publish3():
    '''獲取每個作者合作的出版社(效能一般)'''
    authors = Author.objects.prefetch_related("book_set")
    for author in authors:
        for book in author.book_set.select_related("publish"):
            print(author.name, book.name, book.publish.name)


get_author_publish3()
View Code
'''
[2020-07-27 20:27:04,048] (0.000) SELECT "app01_author"."id", "app01_author"."name", "app01_author"."age" FROM "app01_author"; args=()
[2020-07-27 20:27:04,049] (0.000) SELECT ("app01_book_authors"."author_id") AS "_prefetch_related_val_author_id", "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") WHERE "app01_book_authors"."author_id" IN (1, 2, 3, 4); args=(1, 2, 3, 4)
[2020-07-27 20:27:04,051] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id", "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id") WHERE "app01_book_authors"."author_id" = 1; args=(1,)
金庸 天龍八部 上海商務出版社
金庸 神鵰俠侶 北京大學出版社
[2020-07-27 20:27:04,051] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id", "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id") WHERE "app01_book_authors"."author_id" = 2; args=(2,)
倪匡 天龍八部 上海商務出版社
[2020-07-27 20:27:04,052] (0.000) SELECT "app01_book"."id", "app01_book"."name", "app01_book"."price", "app01_book"."pub_date", "app01_book"."publish_id", "app01_publish"."id", "app01_publish"."name", "app01_publish"."city" FROM "app01_book" INNER JOIN "app01_book_authors" ON ("app01_book"."id" = "app01_book_authors"."book_id") INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id") WHERE "app01_book_authors"."author_id" = 3; args=(3,)
武沛齊 Python入門 清華大學出版社
武沛齊 Python精通 清華大學出版社
'''
輸出結果