如何保存,处理订单中的订单总金额,ordersDetails架构?

时间:2018-02-22 10:45:25

标签: php mysql sql database-design

几个月前,当我开始设计应用程序数据库模式时,我被告知不要在数据库中的多个位置存储相同的数据/ 计算数据(规范化)。如果我这样做,当我在一个地方更新数据而另一个没有更新时,我会做出一些bug。所以我做了一个订单表和ordersDetails表。像这样......

-- orders table
+-----+---------+----------+
| ID  | clintID |   date   |
+-----+---------+----------+
|  1  |    1    |2018-02-22|
|  2  |    1    |2018-02-23|
|  3  |    2    |2018-02-24|
+-----+---------+----------+
-- orderDetail table
+-----+---------+------------+----------+----------+
| ID  | orderID | itemNumber | quantity | unitPrice|
+-----+---------+------------+----------+----------+
|  1  |    1    |   12345    |    3     |  100.75  |
|  2  |    1    |   12346    |    3     |  100.75  |
|  3  |    2    |   12347    |    3     |  100.75  |
|  4  |    2    |   12345    |    3     |  100.75  |
|  5  |    3    |   12347    |    3     |  100.75  |
|  6  |    3    |   12345    |    3     |  100.75  |
+-----+---------+------------+----------+----------+

为了让我更容易查询,我提出了一个观点" allOrdersSummary"像

-- allOrdersSummary
SELECT 
    orders.*, SUM(orderDetail.quantity * orderDetail.unitPrice) totalAmount
FROM orders INNER JOIN orderDetail ON orders.ID = orderDetail.orderID 
GROUP BY orders.ID;

我稍后使用此视图查询,但现在我开始收到MAX_JOIN_SIZE错误。

所以我考虑将计算的总订单金额与订单表ID, clintID, date, totalAmount一起保存,每当我更改orderDeatils表中的内容时,我都会更新订单表中的计算totalAmount列,我不知道这是好还是坏!

这个问题 - 我不知道这是否被认为是一个问题 - 多次遭遇,例如知道客户端的未读消息,我必须要求做sum(messages) unread from messages where to = ? and isRead = 0

A)我应该在订单表中为计算的totalAmount创建另一列,或者在数据库中从totalAmount计算orderDetails是正常的事情。我每次需要它时都会表?

B)如果您建议在订单表中创建另一列,每次orderDetails表中发生更改时,更新它的最佳方法是什么?每当我更新orderDetails表时,我应该在PHP层更新它,还是需要存储过程?

2 个答案:

答案 0 :(得分:1)

是的,根据数据库中的其他数据将预先计算的值存储在数据库中是正常的。但不一定是你提到的原因。我从未遇到MAX_JOIN_SIZE的问题。

存储计算值的主要原因(可能是唯一原因)是速度。因此,您可以针对那些经常不会更改的值进行操作,这些值可能会在使用大量数据的查询中使用,因此如果您不使用它们可能会太慢。

例如:如果您想知道数据库中所有订单的平均值,那么如果您已经拥有订单总数,那么查询会快得多。

为什么以及如何更新值完全取决于您。但是你必须保持一致。如果使用MVC模式,将它集成到控制器中是有意义的。或者简单来说:每当提交的表单可以更改其中一个值时,计算出预先计算的值,就需要重新计算它。

这是一个明确的示范,其中'标准化'没有完全维护。它不是很漂亮,但有时候值得。当然,您可以争辩说,计算出的值代表了新的'信息,因此不会冒犯正常化'。

答案 1 :(得分:1)

你有“膨胀 - 放气”问题。

  1. JOIN这两个表构成了一个更大的临时表。
  2. GROUP BY缩小回原始(orders)表格的每一行。
  3. 这可以避免这个问题:

    SELECT  *,
            ( SELECT SUM(quantity * unitPrice
                  FROM orderDetail  WHERE orderID = orders.ID
            ) AS totalAmount
        FROM  orders;
    

    请告诉我您对此的体验。这是膨胀 - 放气问题最简单的例子之一。