我正在构建一个管理应用程序,以帮助管理我的移动汽车美容公司(可能还有其他公司)。我正在努力弄清楚如何对一些数据建模。

这个问题与我之前发布的一个问题有关,但是我复制了以下相关信息:
Database design - google app engine

在此应用程序中,存在“约会”和“订单项”的概念。

任命是期望员工提供服务的地点和时间。

订单项是一项服务,费用或折扣及其相关信息。约会中可能包含的订单项示例:

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

In my previous implementation of this application, Line Items were contained by a single appointment. This worked fine most of the time, but caused problems sometimes. An example would be if an appointment got interrupted half-way through because of rain and the technician had to come back out the next day and finish up. This situation required two appointments for the same line item. In cases like this, I would just fudge the data a little by setting the "line item" on the second appointment to read something like "Finish Up" and then the cost would be $0.

In this next version, I am considering enabling Line Items to be matched with more than one appointment with a table structure that looks like this:

Appointment
 start_time
 etc...

Line_Item
 appointment_Key_List
 name
 price
 etc...

这种结构的一个普遍问题是它很复杂,我甚至不确定它是否适合将一个订单项与多个约会匹配。如果订单项只能是一个约会的一部分,那么实际上我可以在每个约会中放一个订单项列表,当我得到约会时,我已经在获取订单项。

一个更具体的问题是我正在使用Google App Engine,并且如果我要查询一组约会及其关联的订单项,则必须先查询该约会组,然后再对该行进行第二次查询项使用IN运算符来测试Line_Item的任何约会键是否落入从上一个查询返回的约会键集中。如果我有30个以上的键需要我对查询进行分片,则第二个查询将失败。我可以对数据进行非规范化处理以避免这种复杂而广泛的读取查询,无论如何我可能都必须进行某种程度的非规范化处理,但是我宁愿在适当的情况下避免复杂性。

我的问题是通常如何模拟这种情况?将一个订单项与多个约会配对甚至是合适的做法,还是将每个订单项分别分割为多个项目(例如“两天的工作的第一天”和“两天的工作的第二天”)是否正常? 。”类似的成功应用程序如何做到这一点?这种情况下的经验法则是什么?事实证明,哪些实现的问题较少?

谢谢!

最佳答案

您建议的方法会很好;您可以将订单项的“appointment_Key_list”建模为列表属性,它将按预期工作。您不必使用IN运算符-用于将数据存储区中的单个值与您拥有的键列表进行匹配(例如,“WHERE datastore_column IN('a','b','c')”),而您正在做相反的工作-将单个值与数据存储区中的列表进行匹配。

不过,我建议相反的做法可能更适合您的任务:让每个约会都有一个行项键列表。这的操作方式大致相同,但是要检索约会中的所有数据,您首先要获取约会,然后使用约会实体中的键对订单项进行批量获取。如果您知道约会的关键,那么您就根本不需要进行任何查询。

我一直在尝试向Pindatjuh解释为什么查询列表属性的效率不低于单值属性,但是显然需要更详细的描述,因此,不费吹灰之力,这里是...

App Engine数据存储区索引的简要入门

尽管Python和Java为数据存储区提供了各种高级接口(interface),但是数据存储区本身来说是一个较低层的抽象,称为实体。实体包含以下内容:

  • 唯一的主键
  • (名称,值)对的列表

  • 主键是您已经熟悉的数据存储键。 (名称,值)对的列表是App Engine对您实体中数据的表示。到目前为止,非常简单。具有以下值的实体:
    a_string = "Hello, world"
    an_int = 123
    

    将被序列化为类似于以下内容的东西:
    [('a_string', 'Hello, world'), ('an_int', 123)]
    

    但这如何与列表交互?好吧,列表被视为“多值”属性。即,具有n个项目的列表存储为n个单独的属性。一个例子可能使这一点更清楚:
    a_string = "Hello, world"
    an_int = 123
    a_list_of_ints = [42, 314, 9]
    

    将序列化为:
    [('a_string', 'Hello, world'), ('an_int', 123), ('a_list_of_ints', 42), ('a_list_of_ints', 314), ('a_list_of_ints', 9)]
    

    如您所见,列表代表了一系列值,所有值都具有相同的名称。从数据存储区加载数据时,SDK会看到重复的值并将其转换为列表。

    当它与索引交互时,这一点变得很重要。假设您在“a_string”和“an_int”上有一个索引。当您插入或修改值时,App Engine会为其生成一组索引条目;对于上面的索引和上面的实体,它在索引中生成一个单行,看起来像这样:
    ('Hello, world', 123, a_key)
    

    (这里的“a_key”是原始实体的键的占位符。)执行使用此索引的查询时,只需要对索引进行查找即可找到具有适当前缀的行(例如,“SELECT * FROM Kind WHERE a_string =“你好,世界” ORDER BY an_int')。

    但是,当您为列表建立索引时,App Engine会插入多个索引行。 “an_int”和“a_list_of_ints”上的索引将为上述实体生成以下行:
    (123, 42, a_key)
    (123, 314, a_key)
    (123, 9, a_key)
    

    同样,查询的工作方式与以前相同-App Engine只需在索引中查找具有正确前缀的行。列表中的条目数量对查询的速度没有影响-仅影响生成和写入索引条目所花费的时间。实际上,查询计划者不知道'a_list_of_ints'是一个多值属性-就像对待其他任何索引条目一样。

    简而言之:
  • 在索引和查询术语
  • 中,一个包含一个元素的列表和一个单独的属性之间没有实际区别。
  • 索引列表的大小会影响索引(而不是查询)所需的时间和空间。
  • 您可以使用简单的相等过滤器进行查询,以匹配列表中具有给定值的任何实体。
  • 关于java - 预约和订单项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3125115/

    10-10 19:47