用于计费的高效数据库设计

时间:2015-08-11 06:56:43

标签: mysql database-design

我的要求很简单,但设计经验不足。

每个客户要求旋转照片的费用为1美分。我需要在表中添加每个请求以用于历史记录:

CREATE TABLE Rotate_Photo
(
license VARCHAR(35),
reqtype INT NOT NULL, --each will cost 1 cent
updated TIMESTAMP,
FOREIGN KEY (license) 
        REFERENCES customer(license)
        ON DELETE CASCADE
        ON UPDATE CASCADE
)ENGINE=InnoDB;

现在,另一个付款表将为每个客户保留贷方余额。

CREATE TABLE Payments (
license VARCHAR(35),
Amount FLOAT(5,0) NOT NULL,
receive_date DATE NOT NULL,
updated TIMESTAMP,
FOREIGN KEY (license) 
        REFERENCES customer(license)
        ON DELETE CASCADE
        ON UPDATE CASCADE
) ENGINE=InnoDB;

我怎么知道客户什么时候失去平衡?鉴于服务器每秒都会收到很多请求。

如果有请求,我可以汇总Rotate_Photo中的所有记录,以了解已收到多少请求,并减去客户信用。但它效率不高吗?

有什么更好的方法?

2 个答案:

答案 0 :(得分:1)

选项1

正如你所说

  

付款表将保留贷方余额

因此,当收到请求时,您需要咨询客户的余额并检查是否有正数。

SELECT Amount from Payments where license = :Rotate_Photo.licence;

您可以使用count()函数以有效的方式从Rotate_Photo获取记录数。

SELECT count(*) AS rotation_count from Payments where license = :Rotate_Photo.licence;

选项2

更有效的设计可能是与许可证记录保持平衡。

然后您将拥有许可证表:

CREATE TABLE Payments (
license VARCHAR(35),
Amount FLOAT(5,0) NOT NULL,  -- current balance
purchased_amount FLOAT(5,0),  -- amount purchased so far
receive_date DATE NOT NULL,
updated TIMESTAMP,
FOREIGN KEY (license) 
        REFERENCES customer(license)
        ON DELETE CASCADE
        ON UPDATE CASCADE
) ENGINE=InnoDB;

显然,您每次购买时都必须管理金额和purchase_amount字段(减少金额并增加purchase_amount)。

此方法的缺点是您无法获取特定时间段(例如一个月)的统计信息,但您可以获取该帐户的快照。

优点是您需要一次读取和更新才能管理金额。

答案 1 :(得分:1)

“更好”是主观的 - 但我强烈建议首先构建一个规范化的解决方案(这意味着即时计算余额),并且只有在遇到性能问题时才能进行反规范化,而无法通过更好的查询解决,归档策略,或更大的硬件。

在现代系统上,这可能意味着数万或数亿的记录。

如果您真的对此感到担心,请构建一个测试工具,其中包含您希望在生产中获得的记录数量的两倍,并查看应用程序的执行情况。

您担心的性能问题有很多解决方案。

最常见的是“非规范化” - 每次用户付费或使用该服务时,您都会更新其个人资料中的“currentBalance”字段。您可以在应用程序逻辑中或使用数据库触发器执行此操作。应用程序逻辑意味着处理资金的每一段代码都需要正确执行;只有一个bug可能意味着你放弃了免费的图像旋转。数据库触发器很难测试,难以维护,并且可能会产生自己的性能问题。