2012-01-20 40 views
1

將另一個使用memcache保存數據庫查詢的函數覆蓋get_by_key_name是否有意義?像下面一樣?在這個例子中的memcache鍵只包括實體KEY_NAME的只是爲了簡單...覆蓋get_by_key_name()以使用memcache

class Entity(db.Model): 
    @classmethod 
    def get_by_key_name(cls, key_name): 
    entity = memcache.get(key_name) 
    if entity is not None: 
     return entity 
    else: 
     entity = cls.__super__.get_by_key_name(key_name) 
     memcache.add(key_name, entity, 3600) 
     return entity 
+1

「Override」not「overwrite」 – kindall

+1

cls .__ super __。get_by_key_name'正確拼寫super(Entity,cls).get_by_key_name'。 –

+0

好評傢伙,儘管這很快。 –

回答

2

一個更好的更好的解決方案是使用NDB,它內置了對memcache和實例內存緩存的支持。

2

是否有意義取決於:

  1. 無論您的應用程序的性能不夠好(你的性能目標是什麼,你如何衡量它?)
  2. 數據庫查詢是否真的是你的應用程序的瓶頸(性能問題實際上可能存在於其他地方,直到你簡介纔會知道)
  3. 是否memca che查詢實際上比數據庫的緩存(如果有的話)和多少(數據庫中相同記錄的重複查詢很可能來自RAM)要快得多
  4. 您的應用程序的查詢模式如果記錄不在memcache中,實際上每個查詢都會執行更多的工作,所以如果大多數查詢都是唯一的,那麼它甚至可能會變得更慢! - 數據庫的緩存也可能已足夠)

有人可能已經爲Google App Engine測量了一些此類信息,但#4仍然是您需要爲您的應用程序弄清楚的事情。換句話說,如果沒有更多的數據,這不是一個可以回答的問題。不過,希望我已經給你一些地方開始調查。

根據您對數據庫和SQL的瞭解程度,還可以通過更好地使用數據庫來加快查詢速度,而不會將緩存複雜化添加到您的應用程序中(對GAE並沒有足夠的瞭解,知道它可以讓你做多少)。

至於你提出的實現,這看起來不合理,因爲get_by_key_name()已經是一個類方法。您可能會嘗試將您的新方法直接注入現有的Model類(或將您的整個子類替換回模塊中),因此您不需要更改使用Model的任何代碼。但是這有它自己的危險。當然,你有足夠的好處,你可以做一些測試,看看它是否真的有幫助。

+2

嗯,我認爲這裏有兩個可能的問題:「使用memcache緩存數據庫實體的關鍵是否有意義」(關於如何確定特定應用程序和實體類型,您已經回答了這個問題),以及「這樣做是否合理?「(你沒有提到)。 –

+0

好點。我已經解決了這個問題。 – kindall

0

我也使用memcache來緩存實體,我認爲加快數據庫操作是個好主意。 我選擇將get_key方法添加到類模型,因爲memcache/datastore代理可以在許多類中重用。

定義一個通用的memcache DB代理

#mydb.py 
def get_cache(keys): 
    """ not support async operation 
    because Async operation conflict with cache logiclly 
    """ 
    if not isinstance(keys, list) and not isinstance(keys, tuple): 
     keys = [keys] 

    keys = [str(k) for k in keys] 
    results = memcache.get_multi(keys) #@UndefinedVariable 
    keys_not_in_cache = [k for k in keys if k not in results] 

    if keys_not_in_cache: 
     values = db.get([db.Key(k) for k in keys_not_in_cache]) 
     results_from_db = dict(zip(keys_not_in_cache, values)) 
     results.update(results_from_db) 
     memcache.set_multi(results_from_db) #@UndefinedVariable 

    return [results[k] for k in keys]   

def put_cache(values): 
    """ Not support async operation 
    """ 
    if not isinstance(values, list): 
     values = [values] 

    db.put(values) 

    keys_str = [(str(k.key()), k) for k in values] 
    memcache.set_multi(dict(keys_str)) #@UndefinedVariable  

def delete_cache(values): 
    """ Not Support Async Operation 
    """ 
    if not isinstance(values, list): 
     values = [values] 

    db.delete(values) 

    keys_str = [str(k.key()) for k in values] 
    memcache.delete_multi(keys_str) #@UndefinedVariable 

用法示例

# for the class want to use this feature 
class User(db.Model): 
    email = db.EmailProperty() 

    @classmethod 
    def get_key(cls, email): 
     return db.Key.from_path(cls.__name__, email) 

# Using memcache db proxy 
user_keys = [User.get_key(USER_EMAIL_ADDRESS) for USER_EMAIL_ADDRESS in ALL_USER_EMAIL_ADDRESS] 
users = mydb.get_cache(user_keys) 
1

緩存的想法是好的(但正如其他人已經表明,你必須要小心無效) 。不過,我不會重寫get_by_name()來做到這一點。我會編寫單獨的函數來處理緩存,因此您的代碼讀者可以清楚地看到您沒有使用標準的get_by_name()。還要注意的是,get_by_name()是一個非常薄的get()與Key對象之上的層 - 您應該也可以提供該API。