我的要求很简单,但设计经验不足。
每个客户要求旋转照片的费用为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中的所有记录,以了解已收到多少请求,并减去客户信用。但它效率不高吗?
有什么更好的方法?
答案 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可能意味着你放弃了免费的图像旋转。数据库触发器很难测试,难以维护,并且可能会产生自己的性能问题。