我正在尝试使用GAE数据存储进行一些实践,以了解查询和计费机制。
我读过Oreilly关于GAE的书,也看过关于数据存储的Google视频。我的问题是,最佳实践方法通常涉及更多的读取,而不是写入数据存储。
我开发了一个超级简单的应用程序:
在这种情况下,由于用户可以选择他想要的链接,所以只要他愿意,我的应用程序就会写入数据存储,远远超过读取的次数(当用户选择另一个链接时,写入;当用户打开网页查看他的“链接提要”时)。
问题1:我可以(至少)想到两个选项来处理这个应用程序的数据::
选项A:-使用用户详细信息、注册等维护每个用户的实体--维护每个用户保存其最近选择的10个链接的另一个实体,该链接将在用户请求后呈现到用户的网页上
选项B:-维护每个url链接的实体--这意味着所有用户的所有url都将存储为同一个对象--维护每个用户的详细信息(与选项A相同),但在url的大表中添加对用户url的引用
更好的方法是什么?
问题2:如果我想计算到今天为止选择的urls总数,或者用户选择的每日urls数量,或者任何其他计数--我应该在SDK工具中使用它,还是应该在上面描述的实体中插入计数器?(我希望尽可能减少数据存储的写入量)
编辑(回答@Elad的评论):假设我只想保存每个用户的最后10个urls。剩下的部分我想要去掉(这样就不会用不必要的数据过多地填充我的DB )。
编辑2:在添加代码之后,我使用以下代码进行了尝试(尝试first的方法):
这是我的课:
class UserChannel(db.Model):
currentUser = db.UserProperty()
userCount = db.IntegerProperty(default=0)
currentList = db.StringListProperty() #holds the last 20-30 urls然后,我将url &元数据序列化为JSON字符串,用户将其从第一页中发布。下面是这篇文章的处理方式:
def post(self):
user = users.get_current_user()
if user:
logging messages for debugging
self.response.headers['Content-Type'] = 'text/html'
#self.response.out.write('<p>the user_id is: %s</p>' % user.user_id())
updating the new item that user adds
current_user = UserChannel.get_by_key_name(user.nickname())
dataJson = self.request.get('dataJson')
#self.response.out.write('<p>the dataJson is: %s</p>' % dataJson)
current_user.currentPlaylist.append(dataJson)
sizePlaylist= len(current_user.currentPlaylist)
self.response.out.write('<p>size of currentplaylist is: %s</p>' % sizePlaylist)
#whenever the list gets to 30 I cut it to be 20 long
if sizePlaylist > 30:
for i in range (0,9):
current_user.currentPlaylist.pop(i)
current_user.userCount +=1
current_user.put()
Updater().send_update(dataJson)
else:
self.response.headers['Content-Type'] = 'text/html'
self.response.out.write('user_not_logged_in')其中Updater是我用Channel-API更新网页和提要的方法。
现在,这一切都能工作,我可以看到每个用户都有一个带有20-30链接的ListProperty (当它点击30时,我用pop()将它减少到20 ),但是!价格很高..。像这里的每个帖子都需要200 the,121个cpu_ms,cpm_usd= 0.003588。这是非常昂贵的考虑到我所做的只是保存一个字符串到列表..。我认为问题可能是实体与大ListProperty一起变得更大?
发布于 2011-04-09 12:54:47
首先,对于GAE数据存储的大量写入您是正确的--我自己的经验是,与读取相比,它们非常昂贵。例如,我的一个应用程序除了在一个模型表中插入记录之外什么也不做,达到了免费的配额,每天只写几个10行。因此,有效地处理写操作可以直接转化为您的底线。
第一个问题
我不会将链接存储为单独的实体。数据存储不是一个RDBMS,因此标准的规范化实践不一定适用。对于每个用户实体,使用一个ListProperty存储最新的URL及其元数据(您可以将所有内容序列化为一个字符串)。
另一个优化的想法是:如果用户通常在短时间内添加几个链接,您可以尝试批量而不是单独地编写它们。使用memcache存储新添加的用户URL,任务队列定期将该瞬态数据写入持久数据存储。不过,我不知道使用任务的资源成本是多少--您必须检查一下。这是一篇好文章阅读这一主题。
第二个问题
使用计数器。请记住,它们在分布式环境中并不是微不足道的,所以请仔细阅读--有许多关于这个主题的GAE文章、食谱和博客文章--只有google应用程序计数器。在这里,使用memcache也应该是一个很好的选择,以减少数据存储写入的总数。
发布于 2011-04-09 08:08:36
答案1
将链接存储为单独的实体。另外,用ListProperty存储每个用户的实体,其中包含最近20个链接的键。当用户选择更多的链接时,您只需更新键的ListProperty。ListProperty维护顺序,所以只要您遵循FIFO插入顺序,就不需要担心所选择的链接的时间顺序。
当您想要显示用户选择的链接(第2页)时,您可以执行一个get(键)操作,在一个调用中获取所有用户的链接。
答案2
当然保留计数器,随着实体数量的增加,计数记录的复杂性将继续增加,但是对于计数器,性能将保持不变。
https://stackoverflow.com/questions/5603591
复制相似问题