如何减少对Google App Engine数据存储区的读写次数

时间:2014-10-23 14:30:55

标签: google-app-engine google-cloud-datastore

我很感激,如果你可以帮助我在我非常简单的应用程序"中最小化读写次数。我是新手,所以请保持温柔:)

我的应用程序基本上是一个测验, ~120个问题,每页约20页~~ 6个问题全部写入同一个"表" 。根据我的学生回答某些问题的方式,他们将被发送回早期的问题或后续问题的措辞可能会改变。在测验结束时,应用程序会根据正确回答的问题数量计算每个学生的分数。

当超过40人同时或在同一天参加测验时,问题就开始了。我收到有关超过配额以及对数据存储区的读写次数的错误消息。

如果我理解正确,我的数据库太大会导致爆炸搜索:https://cloud.google.com/appengine/articles/

将数据库拆分为20个问题的20个数据库会解决问题吗?

我必须在星期三之前让它工作,我自己没有办法测试这个解决方案。

谢谢!

以下是我创建数据库的方法:

class ExpQuestionnaires(db.Model):
    created = db.DateTimeProperty(auto_now_add = True)
    username= db.StringProperty(required=False)
    nmi1 = db.StringProperty(required=False)
    nmi2 = db.StringProperty(required=False)
    nmi3 = db.StringProperty(required=False)
    nmi_happy = db.StringProperty(required=False)
    nmi_pleasant = db.StringProperty(required=False)
    nmi_good = db.StringProperty(required=False)
    nmi_interested = db.StringProperty(required=False)    
    ai_content = db.TextProperty(required=False)
    aic = db.TextProperty(required=False)
    dm1 = db.StringProperty(required=False)
    dm2 = db.StringProperty(required=False)
    dm3 = db.StringProperty(required=False)
    dm4 = db.StringProperty(required=False)
    dm5 = db.StringProperty(required=False)
    dm6 = db.StringProperty(required=False)
    dm7 = db.StringProperty(required=False)
    dm8 = db.StringProperty(required=False)
    dm9 = db.StringProperty(required=False)
    dm10 = db.StringProperty(required=False)
    dm11 = db.StringProperty(required=False)
    dm12 = db.StringProperty(required=False)
    dm13 = db.StringProperty(required=False)
    dm14 = db.StringProperty(required=False)
    dm15 = db.StringProperty(required=False)
    dm16 = db.StringProperty(required=False)
    dm17 = db.StringProperty(required=False)
    dm18 = db.StringProperty(required=False)
    dm19 = db.StringProperty(required=False)
    dm20 = db.StringProperty(required=False)
    dm21 = db.StringProperty(required=False)
    dm22 = db.StringProperty(required=False)
    dm23 = db.StringProperty(required=False)
    dm24 = db.StringProperty(required=False)
    dm25 = db.StringProperty(required=False)
    dm26 = db.StringProperty(required=False)
    dm27 = db.StringProperty(required=False)
    dm28 = db.StringProperty(required=False)
    dm29 = db.StringProperty(required=False)
    dm30 = db.StringProperty(required=False)
    dm31 = db.StringProperty(required=False)
    dm32 = db.StringProperty(required=False)
    dm33 = db.StringProperty(required=False)
    dm34 = db.StringProperty(required=False)
    dm35 = db.StringProperty(required=False)
    dm36 = db.StringProperty(required=False)
    soep1 = db.StringProperty(required=False)
    soep2 = db.StringProperty(required=False)
    soep3 = db.StringProperty(required=False)
    soep4 = db.StringProperty(required=False)
    RteM1 = db.StringProperty(required=False)
    RteM2 = db.StringProperty(required=False)
    RteM3 = db.StringProperty(required=False)
    RteM4 = db.StringProperty(required=False)
    loc1 = db.StringProperty(required=False)
    loc2 = db.StringProperty(required=False)
    loc3 = db.StringProperty(required=False)
    loc4 = db.StringProperty(required=False)
    loc5 = db.StringProperty(required=False)
    loc6 = db.StringProperty(required=False)
    loc7 = db.StringProperty(required=False)
    loc8 = db.StringProperty(required=False)
    loc9 = db.StringProperty(required=False)
    loc10 = db.StringProperty(required=False)
    loc11 = db.StringProperty(required=False)
    loc12 = db.StringProperty(required=False)
    loc13 = db.StringProperty(required=False)
    loc14 = db.StringProperty(required=False)
    loc15 = db.StringProperty(required=False)
    loc16 = db.StringProperty(required=False)
    loc17 = db.StringProperty(required=False)
    loc18 = db.StringProperty(required=False)
    loc19 = db.StringProperty(required=False)
    loc20 = db.StringProperty(required=False)
    loc21 = db.StringProperty(required=False)
    loc22 = db.StringProperty(required=False)
    loc23 = db.StringProperty(required=False)
    loc24 = db.StringProperty(required=False)
    loc25 = db.StringProperty(required=False)
    loc26 = db.StringProperty(required=False)
    loc27 = db.StringProperty(required=False)
    loc28 = db.StringProperty(required=False)
    loc29 = db.StringProperty(required=False)
    bis1 = db.StringProperty(required=False)
    bis2 = db.StringProperty(required=False)
    bis3 = db.StringProperty(required=False)
    bis4 = db.StringProperty(required=False)
    bis5 = db.StringProperty(required=False)
    bis6 = db.StringProperty(required=False)
    bis7 = db.StringProperty(required=False)
    bas1 = db.StringProperty(required=False)
    bas2 = db.StringProperty(required=False)
    bas3 = db.StringProperty(required=False)
    bas4 = db.StringProperty(required=False)
    rei1 = db.StringProperty(required=False)
    rei2 = db.StringProperty(required=False)
    rei3 = db.StringProperty(required=False)
    rei4 = db.StringProperty(required=False)
    rei5 = db.StringProperty(required=False)
    rei6 = db.StringProperty(required=False)
    rei7 = db.StringProperty(required=False)
    rei8 = db.StringProperty(required=False)
    rei9 = db.StringProperty(required=False)
    rei10 = db.StringProperty(required=False)
    imp1 = db.StringProperty(required=False)
    imp2 = db.StringProperty(required=False)
    imp3 = db.StringProperty(required=False)
    imp4 = db.StringProperty(required=False)
    imp5 = db.StringProperty(required=False)
    imp6 = db.StringProperty(required=False)
    imp7 = db.StringProperty(required=False)
    imp8 = db.StringProperty(required=False)
    imp9 = db.StringProperty(required=False)
    imp10 = db.StringProperty(required=False)
    imp11 = db.StringProperty(required=False)
    imp12 = db.StringProperty(required=False)
    demo1 = db.StringProperty(required=False)
    demo2 = db.StringProperty(required=False)
    demo3 = db.StringProperty(required=False)
    demo4 = db.StringProperty(required=False)
    demo5 = db.StringProperty(required=False)
    demo6 = db.StringProperty(required=False)
    demo7 = db.StringProperty(required=False)
    demo8 = db.StringProperty(required=False)
    demo9 = db.StringProperty(required=False)
    demo10 = db.StringProperty(required=False)
    pQuizAttempts = db.IntegerProperty(required=False)
    eQuizAttempts = db.IntegerProperty(required=False)

以下是我如何保存问题dm1,dm2,dm3,dm4,dm5,dm6的答案:

class RteDM1(Handler):
    def get(self):
        self.render("RteDM1.html")

    def post(self):
        dm1 = self.request.get("DM1")
        dm2 = self.request.get("DM2")
        dm3 = self.request.get("DM3")
        dm4 = self.request.get("DM4")
        dm5 = self.request.get("DM5")
        dm6 = self.request.get("DM6")
        username = self.request.cookies.get('username', 0)

        dmdata = ExpQuestionnaires(username = username, dm1 = dm1, dm2 = dm2, dm3 = dm3, dm4 = dm4, dm5 = dm5, dm6 = dm6)
        dmdata.put()

        next = self.request.get("next")
        if next == "yes":
            self.redirect('/RteDM2')

我不依赖于将数据保存到cookie以使作弊更难(长篇故事),并且在我的应用程序或学生的计算机崩溃时至少得到部分答案。

以下是包含以下问题的网页:

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
        body {width:900px; margin:20px auto 10px;background-color:#F0F8FF; font-size:16px; font-family:Arial;line-height:1.5em; text-align:justify;}
    .screen { text-align:center; font-style: italic; }
    .bold { text-align:center; font-weight: bold; }
    .normal { text-align:center; font-weight: normal; line-height:30px}
    a.next { text-align:center; padding:2px 5px; margin:0 47%; border:3px outset #ddd; background-color:#DDD;text-decoration: none;}
    li {padding:5px 0}
    input {margin:7px 10px 5px 15px}
    input[type="submit"]{margin:15px 47%;}
    .button {margin:15px 47%; width:100px}
    .width1 {width:7% !important;text-align:center;padding:10px 2px;font-size:12px; }
    .width2 {width:50% !important;text-align:left;padding:2px;}
    td {margin:0 5px 0 0}
    table {font-size:12px;  border-collapse:collapse;width:100%;}
    table, th, td {border: 1px solid black;padding:3px 10px;text-align:center;}
   </style>
</head>

<body>
    <p style="text-align:right;font-size:12px">3/17</p>
<p>Instructions</p>

<form method="post">
<p></p><br>
<table>
        <tr>
        <td class="width2"></td>
        <td class="width1">1 <br/>very unlikely</td>
        <td class="width1">2 <br/>unlikely</td>
        <td class="width1">3 <br/>possibly unlikely</td>
        <td class="width1">4 <br/>hard to tell</td>
        <td class="width1">5 <br/>possibly likely</td>
        <td class="width1">6 <br/>likely</td>
        <td class="width1">7 <br/>very likely</td>
      </tr>
      <tr>
        <td class="width2">Scenario 1</td>
        <td><input type="radio" name="DM1" value="1"></td>
        <td><input type="radio" name="DM1" value="2"></td>
        <td><input type="radio" name="DM1" value="3"></td>
        <td><input type="radio" name="DM1" value="4"></td>
        <td><input type="radio" name="DM1" value="5"></td>
        <td><input type="radio" name="DM1" value="6"></td>
        <td><input type="radio" name="DM1" value="7"></td>    
      </tr>
      <tr>
        <td class="width2">Scenario 2</td>
        <td><input type="radio" name="DM2" value="1"></td>
        <td><input type="radio" name="DM2" value="2"></td>
        <td><input type="radio" name="DM2" value="3"></td>
        <td><input type="radio" name="DM2" value="4"></td>
        <td><input type="radio" name="DM2" value="5"></td>
        <td><input type="radio" name="DM2" value="6"></td>
        <td><input type="radio" name="DM2" value="7"></td>    
      </tr>
      <tr>
        <td class="width2">Scenario 3</td>
        <td><input type="radio" name="DM3" value="1"></td>
        <td><input type="radio" name="DM3" value="2"></td>
        <td><input type="radio" name="DM3" value="3"></td>
        <td><input type="radio" name="DM3" value="4"></td>
        <td><input type="radio" name="DM3" value="5"></td>
        <td><input type="radio" name="DM3" value="6"></td>
        <td><input type="radio" name="DM3" value="7"></td>    
      </tr>
            <tr>
        <td class="width2">Scenario 4</td>
        <td><input type="radio" name="DM4" value="1"></td>
        <td><input type="radio" name="DM4" value="2"></td>
        <td><input type="radio" name="DM4" value="3"></td>
        <td><input type="radio" name="DM4" value="4"></td>
        <td><input type="radio" name="DM4" value="5"></td>
        <td><input type="radio" name="DM4" value="6"></td>
        <td><input type="radio" name="DM4" value="7"></td>    
      </tr>
      <tr>
        <td class="width2">Scenario 5</td>
        <td><input type="radio" name="DM5" value="1"></td>
        <td><input type="radio" name="DM5" value="2"></td>
        <td><input type="radio" name="DM5" value="3"></td>
        <td><input type="radio" name="DM5" value="4"></td>
        <td><input type="radio" name="DM5" value="5"></td>
        <td><input type="radio" name="DM5" value="6"></td>
        <td><input type="radio" name="DM5" value="7"></td>    
      </tr>
      <tr>
        <td class="width2">Scenario 6</td
>        <td><input type="radio" name="DM6" value="1"></td>
        <td><input type="radio" name="DM6" value="2"></td>
        <td><input type="radio" name="DM6" value="3"></td>
        <td><input type="radio" name="DM6" value="4"></td>
        <td><input type="radio" name="DM6" value="5"></td>
        <td><input type="radio" name="DM6" value="6"></td>
        <td><input type="radio" name="DM6" value="7"></td>    
      </tr>
</table>
  <p class="button"><button type="submit" name="next" value="yes">Next</button></p> 

2 个答案:

答案 0 :(得分:0)

写入与保存的实体数量相关,读取与您检索的实体数量相关。

我们无法为您重新编写您的申请,但以下是一些节省费用的提示:

  1. 仅在查询中使用的索引属性。所有其他属性都应该是无索引的(索引= False)。此更改将极大地减少数据存储操作的数量和数据的大小。

  2. 无需将所有问题都作为属性放入单个实体中。现在,每当您想要保存对单个问题的响应时,您都会重写整个实体,从而产生所有相应的成本。每个问题应该是一个单独的实体 - 可能是问卷调查实体的子实体。然后,您可以以最低成本单独保存每个响应。此更改很可能会将应用的数据存储操作数量减少10-20倍。

答案 1 :(得分:0)

嗯 - 问题是,每次用户切换到下一页时,您是否需要保存答案? 您还可以将数据保留在服务器(会话对象)上,并仅在流程结束时保存到数据库。

还要确保将索引属性保持在较低水平:

  

新实体投放(每个实体,无论实体大小):每个索引属性值写入2次+写入+每个复合索引值写入1次

没有(直接)需要在问题或页面上编制索引。 当用户返回页面时,您只需检索所有问题,并让后端代码将页面的正确问题发送到前端。

我不是每个问题都写一个单独实体的粉丝 - 这会让你对你的回购做更多的阅读。 此外 - 这是一种非常规范化的方法 - 可能对您的应用无效。

更多地考虑您的架构:您的应用程序是如何使用的? 对我来说最简单的是什么?每个用户进行整个测验的1个实体?每页1个实体?每个问题1个实体。 如果你想限制读写=&gt;根据上面的作者计数选择您需要的设计。 并考虑您需要阅读实体的次数。 只需为每个设计写出1或2个场景并进行数学计算。