這篇文章要介紹的是--儘可能地減少資料查詢、更新的動作,因為 Datastore API 的呼叫次數有限制,而且一個 request 的處理時間也有 30 秒的限制,如果在操作資料時沒有注意到一些細節,可能就會碰到問題。
平行讀取、更新或刪除 data entities
在「避免資料寫入衝突」這篇文章中,提到可以使用 App Engine 所提供的
memcache
API 來作資料快取,這樣也是一種減少呼叫 Datastore API 的策略。除此之外,善加利用每個 data entity 的 key 也可以達到減少呼叫 Datastore API 的目標。例如以下這段程式碼:
...
# 修改許多 data entity
for product in products:
product.price = product.price * 1.1
product.put()
...
在這個例子中,
products
中有多少個 entities,就會呼叫多少次 put()
,但若是將上述的程式碼修改為:...
from google.appengine.ext import db
# 修改許多 data entity
for product in products:
product.price = product.price * 1.1
db.put(products)
由於
db.put()
函式支援 list 資料型態的參數,所以這樣的作法僅會算作一次 Datastore API 的呼叫,比起上述的方式大大節省了 Datastore API 的呼叫次數。讀取資料時也是以此類推,若原本的程式為:
...
products = []
# keys 為一個 key list
for key in keys:
products.append(db.get(key))
也可以改寫成:
...
from google.appengine.ext import db
# keys 為一個 key list
products = db.get(keys)
同理可證,若要同時刪除許多 entities,也可以使用
db.delete
。有效率地使用 GQL
另外,若是要使用
GqlQuery
作資料查詢時,若是只需要取出 entities 的 key 值,在 GQL 查詢語句中僅需取出 __key__
欄位即可:...
from google.appengine.ext import db
product_keys = db.GqlQuery('SELECT __key__ FROM Product WHERE title = :title', title='...')
# 或是 product_keys = Product.gql('WHERE title = :title', title='...', keys_only=True)
如此一來,讀取的時間就會比讀取全部的欄位還要快許多(如果資料量夠多的話...)
另外,若是查詢語句會重複使用,可以將該語句建立成一個
GqlQuery
物件後,再利用 bind()
方法重新利用該查詢語句。例如本來的程式碼可能是:...
from google.appengine.ext import db
conditions = [['x', 'y'], ['1', '2'], .....]
for cond in conditions:
query = db.GqlQuery('SELECT * FROM Foo WHERE first = :first, second = :second', first=cond[0], second=cond[1])
....
如此一來,迴圈每執行一次就會建立一個
GqlQuery
物件,資料查詢會變得很沒有效率,如果碰到這樣的情況,程式碼應該改寫為:...
from google.appengine.ext import db
conditions = [['x', 'y'], ['1', '2'], .....]
prepared_query = db.GqlQuery('SELECT * FROM Foo WHERE first = :first, second = :second')
for cond in conditions:
query = prepared_query.bind(first=cond[0], second=cond[1])
....
如此便能重複利用
GqlQuery
這個物件了。