---------->惰性機制:
所謂惰性機制:Publisher.objects.all()或者.filter()等都只是返回了一個QuerySet(查詢結果集對象),它並不會馬上執行sql,而是當調用QuerySet的時候才執行。
QuerySet特點:
<1> 可迭代的
<2> 可切片
#objs=models.Book.objects.all()#[obj1,obj2,ob3...]
#QuerySet: 可迭代
# for obj in objs:#每一obj就是一個行對象
# print("obj:",obj)
# QuerySet: 可切片
# print(objs[1])
# print(objs[1:4])
# print(objs[::-1])
#objs=models.Book.objects.all()#[obj1,obj2,ob3...]
#QuerySet: 可迭代
# for obj in objs:#每一obj就是一個行對象
# print("obj:",obj)
# QuerySet: 可切片
# print(objs[1])
# print(objs[1:4])
# print(objs[::-1])
QuerySet的高效使用:
<1>Django的queryset是惰性的
Django的queryset對應於數據庫的若干記錄(row),通過可選的查詢來過濾。例如,下面的代碼會得
到數據庫中名字為‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
上面的代碼並沒有運行任何的數據庫查詢。你可以使用person_set,給它加上一些過濾條件,或者將它傳給某個函數,
這些操作都不會發送給數據庫。這是對的,因為數據庫查詢是顯著影響web應用性能的因素之一。
<2>要真正從數據庫獲得數據,你可以遍歷queryset或者使用if queryset,總之你用到數據時就會執行sql.
為了驗證這些,需要在settings里加入 LOGGING(驗證方式)
obj=models.Book.objects.filter(id=3)
# for i in obj:
# print(i)
# if obj:
# print("ok")
<3>queryset是具有cache的
當你遍歷queryset時,所有匹配的記錄會從數據庫獲取,然后轉換成Django的model。這被稱為執行
(evaluation).這些model會保存在queryset內置的cache中,這樣如果你再次遍歷這個queryset,
你不需要重復運行通用的查詢。
obj=models.Book.objects.filter(id=3)
# for i in obj:
# print(i)
## models.Book.objects.filter(id=3).update(title="GO")
## obj_new=models.Book.objects.filter(id=3)
# for i in obj:
# print(i) #LOGGING只會打印一次
<4>
簡單的使用if語句進行判斷也會完全執行整個queryset並且把數據放入cache,雖然你並不需要這些
數據!為了避免這個,可以用exists()方法來檢查是否有數據:
obj = Book.objects.filter(id=4)
# exists()的檢查可以避免數據放入queryset的cache。
if obj.exists():
print("hello world!")
<5>當queryset非常巨大時,cache會成為問題
處理成千上萬的記錄時,將它們一次裝入內存是很浪費的。更糟糕的是,巨大的queryset可能會鎖住系統
進程,讓你的程序瀕臨崩潰。要避免在遍歷數據的同時產生queryset cache,可以使用iterator()方法
來獲取數據,處理完數據就將其丟棄。
objs = Book.objects.all().iterator()
# iterator()可以一次只從數據庫獲取少量數據,這樣可以節省內存
for obj in objs:
print(obj.name)
#BUT,再次遍歷沒有打印,因為迭代器已經在上一次遍歷(next)到最后一次了,沒得遍歷了
for obj in objs:
print(obj.name)
#當然,使用iterator()方法來防止生成cache,意味着遍歷同一個queryset時會重復執行查詢。所以使
#用iterator()的時候要當心,確保你的代碼在操作一個大的queryset時沒有重復執行查詢
總結:
queryset的cache是用於減少程序對數據庫的查詢,在通常的使用下會保證只有在需要的時候才會查詢數據庫。
使用exists()和iterator()方法可以優化程序對內存的使用。不過,由於它們並不會生成queryset cache,可能
會造成額外的數據庫查詢。
<1>Django的queryset是惰性的
Django的queryset對應於數據庫的若干記錄(row),通過可選的查詢來過濾。例如,下面的代碼會得
到數據庫中名字為‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
上面的代碼並沒有運行任何的數據庫查詢。你可以使用person_set,給它加上一些過濾條件,或者將它傳給某個函數,
這些操作都不會發送給數據庫。這是對的,因為數據庫查詢是顯著影響web應用性能的因素之一。
<2>要真正從數據庫獲得數據,你可以遍歷queryset或者使用if queryset,總之你用到數據時就會執行sql.
為了驗證這些,需要在settings里加入 LOGGING(驗證方式)
obj=models.Book.objects.filter(id=3)
# for i in obj:
# print(i)
# if obj:
# print("ok")
<3>queryset是具有cache的
當你遍歷queryset時,所有匹配的記錄會從數據庫獲取,然后轉換成Django的model。這被稱為執行
(evaluation).這些model會保存在queryset內置的cache中,這樣如果你再次遍歷這個queryset,
你不需要重復運行通用的查詢。
obj=models.Book.objects.filter(id=3)
# for i in obj:
# print(i)
## models.Book.objects.filter(id=3).update(title="GO")
## obj_new=models.Book.objects.filter(id=3)
# for i in obj:
# print(i) #LOGGING只會打印一次
<4>
簡單的使用if語句進行判斷也會完全執行整個queryset並且把數據放入cache,雖然你並不需要這些
數據!為了避免這個,可以用exists()方法來檢查是否有數據:
obj = Book.objects.filter(id=4)
# exists()的檢查可以避免數據放入queryset的cache。
if obj.exists():
print("hello world!")
<5>當queryset非常巨大時,cache會成為問題
處理成千上萬的記錄時,將它們一次裝入內存是很浪費的。更糟糕的是,巨大的queryset可能會鎖住系統
進程,讓你的程序瀕臨崩潰。要避免在遍歷數據的同時產生queryset cache,可以使用iterator()方法
來獲取數據,處理完數據就將其丟棄。
objs = Book.objects.all().iterator()
# iterator()可以一次只從數據庫獲取少量數據,這樣可以節省內存
for obj in objs:
print(obj.name)
#BUT,再次遍歷沒有打印,因為迭代器已經在上一次遍歷(next)到最后一次了,沒得遍歷了
for obj in objs:
print(obj.name)
#當然,使用iterator()方法來防止生成cache,意味着遍歷同一個queryset時會重復執行查詢。所以使
#用iterator()的時候要當心,確保你的代碼在操作一個大的queryset時沒有重復執行查詢
總結:
queryset的cache是用於減少程序對數據庫的查詢,在通常的使用下會保證只有在需要的時候才會查詢數據庫。
使用exists()和iterator()方法可以優化程序對內存的使用。不過,由於它們並不會生成queryset cache,可能
會造成額外的數據庫查詢。

