【问题标题】:Is redundant data always a no-go冗余数据总是不行吗
【发布时间】:2011-12-23 09:44:24
【问题描述】:

我正在开发一个类似商店的系统(使用 PHP 和 MySQL),将发票导出到外部系统。过程是这样的;

  • 客户订购产品并创建发票
  • 为此发票生成 XML 并发送到外部服务器
  • 外部服务器处理 XML 并用另一个 XML 响应
  • 系统处理响应。

对于发送到外部服务器的每个 XML,都会在数据库中创建一条记录,其中包含相应的发票编号和状态(状态最初为 SENT,表示已发送 XML。)在系统处理完响应后状态为SUCCESSERROR。现在,问题是;在某些时候,我想获取状态为SUCCESS 的请求表中没有记录的发票列表。

编辑:如果状态为ERROR,则会对同一张发票提出新请求,因此每张发票可能会有多个请求。

我的订单表有IDInvoiceNumber 列,请求表有IDInvoiceNumberStatus 列,所以要获得提到的列表,我可以这样做:

SELECT InvoiceNumber 
FROM orders AS a
LEFT JOIN requests AS b
    ON a.InvoiceNumber = b.InvoiceNumber
WHERE NOT EXISTS (SELECT ID 
                       FROM requests 
                       WHERE status = "SUCCESS" 
                           AND request.InvoiceNumber = a.InvoiceNumber)

但是,第二个选项是为订单表创建一个额外的列(即requestSucces),如果系统处理相应发票的成功响应,则该列最初为 0 并设置为 1。这将导致更容易和更便宜的查询来获取需要(重新)发送的发票列表 (SELECT invoiceNumber FROM orders WHERE requestSuccess = 0),但是从技术上讲,该字段是多余的。

我的问题是:什么会更好?以具有冗余字段为代价使用简单查询或使用较重的查询并且不会因冗余而污染数据库。当然;如果你们中的任何人知道一个更好的解决方案而不使用冗余,那就更好了。

【问题讨论】:

  • 这对我来说似乎很主观 - 就我个人而言,如果它导致快速查询与慢速查询,我不认为它是多余的 - 但是我不是 DBA,我相信很多人会提供不同的观点
  • 如果避免繁重的查询,我会考虑按照您的建议对数据进行非规范化,尽管您可能会考虑其他优化方式。每张发票是否有多个请求(您的问题不是 100% 清楚)?
  • @liquorvicar;我已经更新了我的问题;每张发票可能有多个请求。

标签: php mysql database-design


【解决方案1】:

当您将状态字段设置为数字 error=0 和 succes=1 时,您可以执行按 invoicenumber 分组的最大状态,以查看哪些发票没有

【讨论】:

  • 然而,我想到了这个选项;还有更多状态(SENT 是我在问题中提到的状态,但还有其他状态)。你认为给他们一个数字并让SUCCESS成为最高的选项是一种选择吗?
  • 我认为这取决于状态的数量以及您如何组合它们。如果你只有发送、成功和错误,我认为你可以这样。如果您将来要添加更多状态,则必须做好准备,以免最大值与新状态发生冲突
  • 我想我会使用这样的东西。
  • 或者将成功设为 0 并按 min(status) 分组。取决于您是否可以处理由零表示的成功!
  • 受这个答案的启发,我将使用每个状态的数字表示。
【解决方案2】:

为了规范化而进行了战争:-)

但是:
由于您要查找未设置为success 的发票,您不能这样做吗?

SELECT InvoiceNumber
FROM requests 
WHERE status != "SUCCESS" 

(注意不等号)

【讨论】:

  • 您好补丁,感谢您的回复,但由于每张发票可能有多个请求,因此很遗憾。
【解决方案3】:

鉴于从您提供的信息来看,您的请求表中似乎总是为每张发票至少有一个条目,您可以从这样的查询中获取您需要的数据:

SELECT InvoiceNumber
FROM Requests AS r_error
LEFT JOIN Requests AS r_success
ON (r_error.InvoiceNumber=r_success.InvoiceNumber AND r_error.status!='SUCCESS'
    AND r_success.status='SUCCESS')
WHERE r_success.InvoiceNumber IS NULL

我不确定它是否会像闪电一样快,但我认为它会比您的初始查询更快(我没有测试过这个理论!)但更重要的是它不使用您的 Orders 表,因此不应该影响处理您的事务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多