几个月前,当我开始设计应用程序数据库模式时,我被告知不要在数据库中的多个位置存储相同的数据/ 计算数据(规范化)。如果我这样做,当我在一个地方更新数据而另一个没有更新时,我会做出一些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层更新它,还是需要存储过程?
答案 0 :(得分:1)
是的,根据数据库中的其他数据将预先计算的值存储在数据库中是正常的。但不一定是你提到的原因。我从未遇到MAX_JOIN_SIZE
的问题。
存储计算值的主要原因(可能是唯一原因)是速度。因此,您可以针对那些经常不会更改的值进行操作,这些值可能会在使用大量数据的查询中使用,因此如果您不使用它们可能会太慢。
例如:如果您想知道数据库中所有订单的平均值,那么如果您已经拥有订单总数,那么查询会快得多。
为什么以及如何更新值完全取决于您。但是你必须保持一致。如果使用MVC模式,将它集成到控制器中是有意义的。或者简单来说:每当提交的表单可以更改其中一个值时,计算出预先计算的值,就需要重新计算它。
这是一个明确的示范,其中'标准化'没有完全维护。它不是很漂亮,但有时候值得。当然,您可以争辩说,计算出的值代表了新的'信息,因此不会冒犯正常化'。
答案 1 :(得分:1)
你有“膨胀 - 放气”问题。
JOIN
这两个表构成了一个更大的临时表。GROUP BY
缩小回原始(orders
)表格的每一行。这可以避免这个问题:
SELECT *,
( SELECT SUM(quantity * unitPrice
FROM orderDetail WHERE orderID = orders.ID
) AS totalAmount
FROM orders;
请告诉我您对此的体验。这是膨胀 - 放气问题最简单的例子之一。