peewee外來鍵效能問題

2022-05-27 06:33:08 字數 3786 閱讀 5987

# **自:

下面討論一下用peewee的些許提高效能的方法。

避免n+1查詢

n+1查詢指的是當應用提交一次查詢獲取結果,然後在取得結果資料集的每一行時,應用至少再次查詢一次(也可以看做是巢狀迴圈)。

大多數情況下,n 查詢可以通過使用sql join或子查詢來避免。資料庫本身可能做了巢狀迴圈,但是它比在你的應用**本身裡做這些n查詢更高效,後者通常會導致與資料庫再次潛在通訊,沒有利用資料庫本身關聯和執行子查詢時會進行切片等優化工作。

peewee提供了幾種api去減輕n+1查詢的行為。再看看貫串我們這篇文件的模型,user和tweet,這部分我們重點講一下一些n+1場景,說明peewee怎麼幫助我們避免n+1查詢。

在一些場景裡,n+1查詢不會明顯表現為顯著地或可測量的效能瓶頸點。它也由你要查詢的資料,使用的資料庫本身,以及執行查詢獲取結果的潛在因素。優化前後可以測試效能,確保和你**的變化相同。

raw執行時也會出現這種情況:

### all_res = results.raw(sql, "2012", "2013","2014", "2015")

列出最近的tweets

tweets時間軸顯示最近使用者的tweets。除了tweet的內容,還要顯示tweet作者的使用者名稱。n+1場景描述為:

獲取最近的10條tweets

每個tweet,查詢作者資訊(10次查詢)

通過用join選擇兩個表,peewee使得在一次查詢裡完成任務:

複製**

query = (tweet

.select(tweet, user) # note that we are selecting both models.

.join(user) # use an inner join because every tweet has an author.

.order_by(tweet.id.desc()) # get the most recent tweets.

.limit(10))

for tweet in query:

print tweet.user.username, '-', tweet.message

複製**

沒有用join時,得到tweet.user.username會觸發一次查詢去解析外來鍵tweet.user從而得到相關聯的user。

由於我們在user上關聯並選擇,peewee自動為我們解析外來鍵。

列出所有使用者和他們的tweets

你想要顯示若干使用者和他們所有的tweets的頁面。n+1場景為:

取得些許使用者。

每個使用者取到他們的tweets。

雖然和上個例子相似,但是重要區別是:我們選擇tweets時,每個tweet只有乙個關聯的使用者,所以可以直接賦值到外來鍵,

反過來不對,因為乙個使用者可有任意數量tweets或者沒有。

peewee提供兩兩種途徑去避免o(n)查詢:

1.首先取到使用者,然後取到關聯這些使用者的所有tweets。一旦peewee取到tweets,將它們與合適的使用者匹配。

這種方法通常很快,但是會在所選擇的每個表上執行一次查詢。

2.在乙個查詢裡得到使用者和tweets。使用者資料將複製,所以peewee將在列舉結果集時減少重複和聚合tweets。

這種方法導致有許多資料需要傳輸,並且要有許多python邏輯去減少行重複。

每種方案根據查詢資料的大小和結構都會可能比另一種更好。

使用prefetch

peewee使用子查詢可以預獲取資料。這種方法需要prefetch特殊api使用。pre-fetch,像其名字本身,

用子查詢去急切載入給定使用者的相應的tweets。意味著我們用o(k)查詢k張表而不是o(n)查詢n行紀錄。

下面演示我們如何得到若干使用者和他們最近一周的tweets:

複製**

week_ago = datetime.date.today() - datetime.timedelta(days=7)

users = user.select()

tweets = (tweet

.select()

.where(

(tweet.is_published == true) &

(tweet.created_date >= week_ago)))

# this will perform two queries.

users_with_tweets = prefetch(users, tweets)

for user in users_with_tweets:

print user.username

for tweet in user.tweets_prefetch:

print ' ', tweet.message

複製**

注意user 查詢和tweet查詢都沒有join子句,當我們使用prefetch時不必指名join

prefetch可以用於任意數量的表。可以檢視api文件看其他例子。

用prefetch時應考慮的事情:

預查詢的模型必須存在外來鍵

通常它比aggregate_rows方法更高效

因為資料沒有重複的所以傳輸的資料更少

因為不用減重複所以python邏輯更少

當你想要在最外的查詢裡使用limit沒問題,但是可能正確的實現限制子查詢的返回結果大小有些困難。

使用aggregate_rows

aggregeate_rows一次在記憶體中減少重複,選擇所有的資料。它和prefetch都可以完成任意複雜的查詢。

使用這個特性需要當建立查詢時用到特殊的標誌aggregate_rows。它告訴peewee減少那些根據join的結構可能會重複的行。

因為在減少重複聚合資料時有許多計算,所以可能使用aggregate_rows可能在一些查詢中會比用prefetch效能低,即使面對的是

o(n)簡單的 查詢時,所以你不確定使用哪種方法時測試檢查你的**。

複製**

query = (user

.select(user, tweet) # as in the previous example, we select both tables.

.join(tweet, join.left_outer)

.order_by(user.username) # we need to specify an ordering here.

.aggregate_rows()) # tell peewee to de-dupe and aggregate results.

for user in query:

print user.username

for tweet in user.tweets:

print ' ', tweet.message

複製**

複製**

query = (user

.select(user, tweet) # as in the previous example, we select both tables.

.join(tweet, join.left_outer)

.order_by(user.username) # we need to specify an ordering here.

.aggregate_rows()) # tell peewee to de-dupe and aggregate results.

for user in query:

print user.username

for tweet in user.tweets:

print ' ', tweet.message

mysql 外來鍵問題

mysql檢視外來鍵的語句 select constraint name from information schema.key column usage where table schema mydb 其中mydb為你的mysql資料庫名稱,查詢的結果是你這個資料庫的所有主外來鍵約束的名稱,或者這...

MySQL 外來鍵問題

清空 刪除具有外來鍵約束的表時報error 1701 42000 的解決 解決方法 解除外來鍵約束 mysql set foreign key checks 0 刪除表後新增外來鍵約束 mysql set foreign key checks 1 查詢外來鍵 select from informat...

關聯 外來鍵問題

外來鍵問題 外來鍵一定是每個表的主鍵關聯問題 兩個表之間有聯絡,是通過外來鍵的設定模型中如果有外來鍵和多對多字段,建立的時候外來鍵必須首先繫結,然後儲存,才能新增多對多字段。relationships 主要有三類 many to one,many to many,one to one class s...