代码之家  ›  专栏  ›  技术社区  ›  Chris Dutrow

数据库设计-谷歌应用引擎

  •  7
  • Chris Dutrow  · 技术社区  · 14 年前

    我正在使用googleappengine并使用低级javaapi访问大表。我正在构建一个具有4层的SAAS应用程序:

    • RESTful资源层
    • 业务层

    我正在构建一个应用程序来帮助管理我的移动汽车公司(以及其他类似的公司)。我必须代表这四个独立的概念,但我不确定我目前的计划是否是一个好的计划:

    • 约会
    • 行项目
    • 付款

    “预约”是指员工为了提供服务而被期望到达的地点和时间。

    行项目: “行项目”是服务、费用或折扣及其相关信息。可能进入约会的行项目示例:

    Name:                          Price: Commission: Time estimate   
    Full Detail, Regular Size:        160       75       3.5 hours 
    $10 Off Full Detail Coupon:       -10        0         0 hours 
    Premium Detail:                   220      110       4.5 hours 
    Derived totals(not a line item): $370     $185       8.0 hours
    

    “发票”是客户承诺支付的一个或多个商品的记录。

    付款: “付款”是对收到的付款的记录。

    在这个应用程序的前一个实现中,生活更简单,我将这四个概念都视为SQL数据库中的一个表:“约会”。一个“约会”可以有多个行项目、多个付款和一个发票。发票只是从行项目和客户记录生成的电子邮件或打印件。

    • 当一位客户预约了一次,但预约中途下雨,导致服务人员第二天必须回来时,我需要两次预约,但只有一个商品、一张发票和一次付款。
    • 当一个办公室里的一群客户为了打折都决定当天把车修好时,我需要一个预约,但需要多张发票和多笔付款。
    • 当一个客户用一张支票支付两次预约的费用时,我需要两次预约,但只有一张发票和一次付款。

    拟议结构:

    下面是用于组织和存储这些数据的规范化结构。也许是因为我的经验不足,我非常重视数据规范化,因为这似乎是避免数据不一致性错误的一个很好的方法。使用这种结构,只需一个操作就可以更改数据,而不必担心更新其他表。然而,读取可能需要多次读取,再加上内存中的数据组织。我在后面想,如果有性能问题,我可以在“Appointment”中添加一些非规范化字段,以便在保持“safe”规范化结构完整的同时更快地进行查询。反规范化可能会降低写操作的速度,但是我认为我可以对其他资源进行异步调用,或者添加到任务中,这样客户机就不必等待额外的写操作来更新数据的反规范化部分。

    Appointment
     start_time
     etc...
    
    Invoice
     due_date
     etc...
    
    Payment
     invoice_Key_List
     amount_paid
     etc...
    
    Line_Item
     appointment_Key_List
     invoice_Key
     name
     price
     etc...
    

    • 查询位于给定范围之间的“开始时间”字段的“约会”列表。
      • 将返回的约会中的每个键添加到列表中。
    • 查询所有“行项目”谁的约会\u键\u列表字段包括任何返回的约会
      • 将所有行项目中的每个发票密钥添加到集合中。
    • 查询发票集中的所有“发票”(这可以使用appengine在一个异步操作中完成)
    • 查询所有“付款”谁的发票\密钥\列表字段包含与任何返回的发票匹配的密钥
    • 在内存中重新组织,以便每个约会都反映为其安排的行项目、总价、总估计时间以及是否已付款的天气。

    有人能对这个设计发表意见吗?这是我能想到的最好的,但我怀疑可能有更好的选择或完全不同的设计,我不认为这可能会更好地工作在一般或特别是在GAE(谷歌应用程序引擎)的优势,弱点和能力。

    谢谢!

    大多数应用程序都是读密集型的,有些则是写密集型的。下面,我将描述一个典型的用例和用户希望执行的分解操作:

    • 阅读 -Manager加载日历并查找可用的时间
    • -经理向客户查询他们的信息,我认为这是一个连续的异步读取,因为经理输入每一条信息,如电话号码、姓名、电子邮件、地址等。。。或者,如果必要的话,在客户端应用程序收集了所有信息并提交之后,在最后写一篇文章。
    • -经理记下客户的信用卡信息,并将其作为单独的操作添加到他们的记录中

    经理拨出电话:

    • 管理器加载日历
    • 经理为他想打电话的客户预约
    • 阅读 呼叫服务器响应呼叫请求并读取CallRecord以了解如何处理呼叫
    • 呼叫服务器将更新的信息写入CallRecord
    • 当调用关闭时,调用服务器向服务器发出另一个请求以更新CallRecord资源(注意:此请求不是时间关键的)

    接受答案: 前两位的回答都非常周到和受人赞赏。为了尽可能不完美地平衡他们的风险敞口,我以很少的票数接受了那个。

    3 回复  |  直到 14 年前
        1
  •  9
  •   David Underhill    14 年前

    您指定了网站需要提供的两个特定“视图”:

    1. 操作的整体视图。我不确定这意味着什么,但是如果您需要执行上面提到的由四个查询组成的字符串来获得它,那么您的设计可能需要一些改进。详情如下。

    不可能的 . 我会仔细检查每个问题:

    1. 从#1获取每个约会的所有行项目-这是个问题。此查询要求您执行 IN 查询。 N sub-queries behind the scenes -因此,您将得到来自#1的每个约会密钥的一个查询!这些将并行执行,所以这不是很糟糕。主要问题是 查询仅限于一小部分值(最多30个值)。如果#1返回的约会密钥超过30个,则此查询将无法执行!

    2. 获取行项目引用的所有发票-没问题。这个查询很便宜,这是正确的,因为您可以通过键直接获取所有相关的发票(注意:这个查询仍然是同步的-我不认为asynchronous是您要找的词)。

    3. 获取#3返回的所有发票的所有付款-这是一个问题。与#2类似,此查询将是 如果#3返回的发票数量适中,您需要为其取款,则查询将失败。

    如果#1和#3返回的项目数量足够少,那么GAE几乎肯定会是 在允许的范围内这样做。这应该足以满足你的个人需求-听起来你主要需要它来工作,而不需要它来扩展到大量的用户(不会)。

    改进建议:

    • 试着把钥匙存起来 Line_Item , Invoice Payment 与指定任命相关的实体在任命本身的列表中。然后你就可以消除 ListProperty 索引以避免问题 exploding indices

    其他不太具体的改进意见:

    • 根据您的“操作的总体视图”将要显示的内容,您可能能够分割所有这些信息的检索。例如,您可以从显示约会列表开始,然后当经理需要有关特定约会的更多信息时,您可以继续获取与该约会相关的信息。如果您希望在单个页面上进行交互,那么甚至可以通过AJAX来实现这一点。
        2
  •  7
  •   Jason Hall    14 年前

    正如你所注意到的,这种设计无法扩展。它需要4(!!!)DB查询以呈现页面。太多了3个:)

    使用appengine数据存储的主流概念是,在编写某些内容时,您希望尽可能多地进行工作,因此在检索和呈现某些内容时,几乎不需要做任何事情。与呈现数据的次数相比,您大概只写了很少的次数。

    正常化同样也是你努力追求的目标。数据存储没有在规范化中放置任何值——这可能意味着更少的数据不一致,但也意味着读取数据要慢很多(4次读取?!!)。由于您的数据读取的频率远高于写入的频率,请针对读取进行优化,即使这意味着您的数据偶尔会被复制或在短时间内不同步。

    与其考虑数据存储时的外观,不如考虑数据显示给用户时的外观。尽可能靠近该格式存储,即使这意味着在数据存储中存储预呈现的HTML。阅读速度会很快,这是一件好事。

    task queue 是给你的。将您认为模型的“基本必需品”存储在数据存储中,然后启动一个任务队列将其拉回来,生成要呈现的HTML,并将其放在后台。这可能意味着在任务完成之前,您的模型可以立即显示,因此在这种情况下,您需要优雅地降级,即使这意味着在数据完全填充之前以“慢方式”渲染它。任何进一步的阅读都将是闪电般的快。

    总之,我没有任何与您的数据库直接相关的具体建议——这取决于您希望用户看到数据时数据的外观。

    可以

    • 布雷特·斯拉特金的 2008 2009 this year 关于数据管道(我认为这不是直接适用的,但通常非常有用)
    • App Engine Under the Covers :App Engine如何在幕后完成它的工作
    • AppStats :这是查看您正在执行多少数据存储读取的好方法,以及有关减少该数量的一些提示
        3
  •  2
  •   Peter Recore    14 年前

    • 使用不等式进行查询时,只能在上使用不等式 one property . 例如,如果您在7月1日和7月4日之间筛选应用程序日期,则不能同时按 price > 200

    • 与您可能习惯的SQL数据库相比,appengine上的事务有点棘手。您只能在同一个实体上进行交易“ entity group