飲冰三年-人工智慧-Python-48 Django ORM 效能優化
阿新 • • 發佈:2020-07-28
這是飲冰三年-人工智慧-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)imodels.py# 建立多對多的方法 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()
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; deletefrom 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精通 清華大學出版社 '''輸出結果