【问题标题】:What is the proper way of storing calculated amounts in database?在数据库中存储计算量的正确方法是什么?
【发布时间】:2020-01-19 09:54:58
【问题描述】:

我有 3 张桌子(customersinvoicesinvoice_items)。

一个客户可以有多个发票,一个发票可以有多个项目。

这是我当前的架构:

客户

id
name
timestamps

发票

id
customer_id
timestamps

invoice_items

id
invoice_id
price
timestamps

注意:时间戳是 created_atupdated_at 字段。不用担心。

如您所见,我没有将发票的总金额存储在 invoices 表中。我让前端计算一下。

现在,我的客户有 1000 多个客户,他们希望在主页上显示所有客户以及他们拥有的所有发票的总和。

ID |客户名称 |总发票(所有发票的总和)

现在我正在使用 Laravel,所以我的查询如下所示:

$customers = Customer::with('invoices.items')->get();

最好的方法是什么?性能方面?

我应该只将每张发票的总金额存储在 invoices 表中,以避免查询项目并计算总和吗?比如:

发票

id
customer_id
total
timestamps

想象一个客户有数千张发票,每张发票有多个项目。查询会很慢,我必须在前端计算每一件事。

此外,发票一经制作,便无法更改。所以发票的总额是静态的。

【问题讨论】:

  • 您可以像使用 SUMCOUNT 聚合函数一样对查询中的所有发票求和。这样就可以得到查询中的所有数据。无需存储在表中。
  • 是的,对于千条记录,前端计算可能会很慢,所以最好在查询中使用聚合函数。对于大量记录,查询将比前端计算相对更快。
  • 您不想存储计算的总数。您必须确保在任何时候发生变化时重新计算它们。正如上面的评论中提到的,如果您的索引是正确的,那么显示客户及其总数的查询应该不会很慢。
  • 我会说是的,因为一旦您说它无法更新,那将是出于某种原因。如果您真的想保存总计,尽管我会将它们放在您的 invoices 表中。鉴于您提供的 3 张桌子,没有其他合乎逻辑的地方。
  • @wobsoriano - 我同意戴夫的观点。

标签: php mysql database laravel uitableview


【解决方案1】:

除了时间戳,它看起来不错。 您不能只在发票表中使用一个时间戳列吗?

为什么需要在所有 3 个表中使用相同的列?

另外,我相信你可以在你的 php 脚本中计算总数。 您不需要在 php 中存储您可以通过 count() 计算的总数。

【讨论】:

    【解决方案2】:

    当然,当您在invoice 表上添加total 列时,您应该会提高性能,因为您不必遍历所有invoice_items 并将它们相加。如果您只需要一次将项目添加到 invoice 并且以后不需要更新,这很好。这样,您将需要在一次生成发票时添加总计。

    【讨论】:

    • 是的,总数是静态的。发票一经开出,便无法更改。
    • 在这种情况下,我认为最好在您的发票表中保留一个总列,因为数据库在获取查询时不需要遍历invoice_items 表的每一行。此外,我认为您应该尝试一次并检查自己。
    【解决方案3】:

    在 invoice 表中添加 total 列对性能肯定有好处,也有助于通过 eloquent 获取结果。但是,如果性能在这里不重要,我们可以不用它来做到这一点。你的 SQL 查询应该是这样的(可能需要很少的调整)

    SELECT c.*, i.*, sum(ii. price) as total_invoice_price
    FROM customers c
    INNER JOIN invoices i on i.customer_id = c.id
    INNER JOIN invoice_items ii on ii.invoice_id = i.id
    GROUP BY i.id
    

    一旦你通过 SQL 获得了预期的结果,你就可以在 laravel 中使用DB::table 运行它。

    【讨论】:

      【解决方案4】:

      这是 WORM(一次写入多次读取)的经典案例。

      让我们来看看这两种方法的优缺点:

      • 案例 1:不在 invoices 表中存储总计

        • 优点:简单易行。没有数据冗余。
        • 缺点:每次计算总计时性能缓慢且消耗资源(内存和 CPU)
      • 案例 2:将总计存储在发票表中

        • 优点:更好的性能,因为“复杂”的发票总计算 只发生一次,后续读取速度更快
        • 缺点:数据冗余并且需要一些额外的存储空间

      现在,如果您研究这两种方法的缺点,情况 2 显然更好,因为可以轻松购买额外的存储空间,但即使您在一定程度上增加 RAM 和 CPU 也无法提高性能。

      【讨论】:

      • 更重要的是,案例 2 留下了更多的维护和应用逻辑,尤其是在创建发票后可以更新行项目的情况下。人们需要一种有效的方法来确保在任何时间行项目发生变化时重新计算发票总额。
      猜你喜欢
      • 2013-02-01
      • 2011-05-29
      • 1970-01-01
      • 2015-03-20
      • 2016-05-31
      • 2020-01-25
      • 1970-01-01
      • 2019-12-10
      • 1970-01-01
      相关资源
      最近更新 更多