【问题标题】:How to store paid and unpaid orders in database?如何在数据库中存储已付款和未付款的订单?
【发布时间】:2015-03-30 15:42:28
【问题描述】:

我正在设计一个数据库,我需要在其中存储 客户的已付款订单未付款订单这两类订单都有 与其他表相同的属性和关系。

我想出了两个设计:

1.两类订单的单独表格:优点:这种设计帮助我快速区分购物车中的订单和已付款的订单。每当客户重新访问我的网站时,我只需查找该特定客户的 UnpaidOrder 表,我的购物车就准备好了。

缺点: 每当为 UnpaidOrder 表中的订单付款时,我需要将相应的行(UnpaidOrder 和与其链接的其他表的)移动到 PaidOrder 表及其对应的表中。此外,这种设计将需要 2 倍数量的表格:例如。 UnpaidOrderDeliveryAddress, UnpaidOrderCreditCard, ... 与 UnpaidOrder 和 PaidOrderDeliveryAddress, PaidOrderCreditCard, ... PaidOrder 的关系。

2。两个类别的公用表和一个额外的状态属性:优点:我不需要在支付未付款订单时移动多行。另外,对应关系的表数减半。

缺点:我为每一行存储了一个额外的 Status 属性。每当客户重新访问我的网站时,我都需要查找 Order 表,并且需要检查该特定客户每一行的 Status 属性(已付款/未付款)。因此,购物车的加载时间会更长。


我的问题是:

  • 考虑到用户众多且应用程序繁重,哪个设计在性能方面更好?
  • 有什么好的替代方案可以满足我的要求吗?

【问题讨论】:

    标签: mysql database database-design relational-database


    【解决方案1】:

    另一种意见....

    不需要额外的规范化表(UnpaidOrderDeliveryAddress, UnpaidOrderCreditCard, ... 对于与 UnpaidOrder 和 PaidOrderDeliveryAddress 的关系, PaidOrderCreditCard, ... 对于 PaidOrder)。如果您认为FOREIGN KEYs 需要这样,我将反对在这种情况下使用FOREIGN KEYs。简单的索引就足够了。

    由于您最终将拥有比“未付费”条目更多的“付费”条目,而付费条目本质上是您很少需要接触的“历史”,因此我倾向于使用 2 个表。

    我可能不会使用触发器——我宁愿在我有更多控制权的应用程序代码中使用它。

    您是否期望每秒执行超过 100 条 SQL 语句?如果不是,我不会称它为“重”。

    请务必用BEGIN..COMMIT 小心地将适当的语句组括起来。此外,在导致 UPDATE 的 SELECT 上使用 FOR UPDATE

    【讨论】:

    • 通过简单的索引,你的意思是我需要为表使用一个公共键(PaidOrder/UnpaidOrder 与 PaidOrder____/UnpaidOrder____ 表有 1 到 0..1 的关系)。如果我使用公共密钥,我将如何将 OrderCreditCard 中的特定记录(因为您说我不需要额外的规范化表)与 PaidOrder/UnpaidOrder 表映射。 OrderCreditCard 中的特定键(如果常见),例如“111”,可能映射到 PaidOrder/UnpaidOrder。换句话说,如果我使用一个公用键并且我希望它工作,那么 PaidOrder 和 UnpaidOrder 中的两个主键不能相同。
    • 另外,您不认为将“付费”记录从“未付费”表移动到“付费”表是一种笨拙的方法吗? PS:我是数据库设计的新手。
    • 一个订单就是一个订单,无论是否支付。创建订单时,为其指定一个唯一的 order_id 并根据需要将 order_id 放入其他表中。同样适用于信用卡等。订单以UnpaidOrders 开始,并获得order_id(可能通过AUTO_INCREMENT)。当它移动到PaidOrders 时,它保持相同的order_id,但不是AUTO_INCREMENT
    • 如果你问我的意见,我比我更喜欢这个答案。
    • 好的。现在我明白了。如果我通过使PaidOrder 而不是AUTO_INCREMENT 以这种方式设计,我将不需要额外的表格。不过我有一个担心。以这种方式将记录从一个表移动到另一个表是一种好习惯吗?
    【解决方案2】:

    如果您担心性能,一个可能的建议是您可以执行类似于第 2 版的操作,但在项目标记为“已付费”时使用触发器运行单独的查询(例如,您可以将已付费指示器保留为在付款之前为 NULL),然后当它被填充时,将它移动到一个单独的表中,就像在版本 1 中一样。

    换句话说,所有项目都将在表 1 中,直到它们被支付,当它们被自动移动到表 2 然后从表 1 中删除。

    CREATE TRIGGER trigger_name
    AFTER UPDATE
       ON `UnpaidOrder`.`paid` FOR EACH ROW
    
    BEGIN
    
       DECLARE vOrder varchar(50);
    
       SELECT order_number() INTO vOrder;
    
       INSERT INTO PaidOrder
       //code here from the first table
    
       DELETE from `UnpaidOrder`  //if you choose to do so, or you could leave it on the table;  up to you
       //criteria that you wish to delete
    
    END;
    

    【讨论】:

    • 你的回答和我的第一个设计有很大区别吗?
    • 哦,现在我仔细看,我认为你是对的。我的错。无论如何,两者之间的权衡似乎很小。我主要关心的是查看用户端。您不希望失去客户,所以如果您必须在装载购物车的时间和完成交易之间的时间之间做出选择,我会选择后者。所以,记住这一点,我更喜欢你的设计 1 方法。
    • 我认为您在最后一句话中的意思是设计“2”方法更好(因为无需将付费交易从 UnpaidOrder 移动到 PaidOrder)。
    • 其实,设计2会让来访的客户变慢,使购物车加载变慢。对于设计 1,购物车已经加载(加载速度会更快,对吗?)在他们点击“购买”之前不会很慢。换句话说,他们已经做出了决定。无论哪种方式,我认为您不会有太多问题(正如另一个答案所建议的那样,除非您期望每秒进行数百次购买:)
    猜你喜欢
    • 2017-06-27
    • 1970-01-01
    • 2012-09-29
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 2022-01-24
    • 2019-05-18
    • 1970-01-01
    相关资源
    最近更新 更多