app engine datastore 效能心得

由於這一陣子用 app engine 寫了一些玩具跟 myaudiocast, 所以來記錄一下心得。雖然 app engine 不用錢, 似乎不用怕資料庫 scale 的問題, 可是比起一般使用關聯式資料庫來說, 開始 run 之前得更仔細規劃, 因為有些資料在寫入後就無法更動了。

上面這張圖是 myaudiocast 簡單的示意圖, 接下來就用這張圖來說一下關於 datastore 使用上的心得

單筆資料 ( one-to-one )

像是 User 對 Podcast 在我的規劃上是 one-to-one, 所以如果是 one-to-one 這類的資料就給定 keyname, 直接用 keyname 來抓單筆資料, 而不是先用 filter 之後在用 get 來取得單筆資料。 因為用 appstats 就發現後面這個方法常常是花最多時間的, 然而因為之前的資料都沒給 key_name 現在也來不及了 …

多筆資料 ( one-to-many, many-to-many )

像是 Episode 這類 one-to-many, 會有多筆的資料, 沒事就不用給 key_name 了, 因為通常都是透過 filter 來取出多筆資料, 所以只需要寫入時指定 parent, 讓 user 的 episodes 可以成為一個 entity group, 這樣抓取資料比較快。

盡量使用 memcache

datastore 其實並沒有很快, 甚至 model api 沒有 query cache, 而 memcache 的 quota 其實滿大的, 所以要盡量用 memcache。

避免在 template 透過關連取資料

像是 podcast 跟 episodes 都可以透過關連, 像是 user.podcast 跟 user.episodes 來取得資料, 所以因為寫 django 的經驗, 我可能就直接丟 user 變數進 template, 然後都用 user.podcast, 跟 user.episodes 來取得資料, 可是這在 app engine 則是要避免的, 因為 app engine 的 model 並沒有 query cache, 所以可能會像下面這樣的作法, 就會對 podcast 做兩次 query。

{{ user.podcast.title }}
{{ user.podcast.description }}```

所以得一開始就把 user 跟 podcast 丟進 template, 直接取得資料而不是透過物件關連。

不過有時候就是一定得透過關連來做, 那麼就請使用 django 1.0 以上的 template, 透過 [with](http://docs.djangoproject.com/en/dev/ref/templates/builtins/#with) 這個 template tag 來避免多次 query, 或者是在 model 新增一個 property 然後用 memcache 來解決, 像是我的作法

class User(db.Model):
...

@property
def podcast(self):
    cache_key = 'user-podcast-%s' % self.key()
    p = memcache.get(cache_key)
    if not p:
        p = self.podcasts.ancestor(self).get()
        memcache.add(cache_key, p)

    return p```

先前說過, 以前不懂忘記給 key_name, 現在只能這樣 query 了, 頂多加上個 ancestor (默)

結論

datastore 雖然不太需要擔心 scale 的問題, 可是在 run 之前卻得更仔細規劃, 否則效能低落, 花的只是更多錢阿 XD 而 memcache 則是一定得用, 否則跑起來的確是不夠快。

大概是這樣, 希望沒有哪裡有寫錯的, 如果有的話, 也請多多留言指指教, 謝謝 :p

tzangms

Read more posts by this author.

Subscribe to Oceanic / 海海人生

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!