Mysql 高效的计费数据库设计

Mysql 高效的计费数据库设计,mysql,database-design,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 DEL

我有一个简单的要求,但设计经验很少

每位客户要求轮换一张照片的费用为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;
我如何知道客户何时失去平衡?考虑到服务器每秒会收到许多请求这一事实

如果有请求,我可以将照片中的所有记录相加,以了解收到了多少请求,然后用客户信用减去。但这不是效率很低吗


什么方法更好?

选项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;
显然,每次购买时,您都必须管理“金额”和“已购买金额”字段(减少金额和增加已购买金额)

这种方法的缺点是,您无法获取特定时间段(例如一个月)的统计数据,但可以获取帐户的快照

这样做的好处是,您需要一次读取和更新来管理金额

“更好”是主观的——但我强烈建议首先构建一个规范化的解决方案(这意味着在运行中计算平衡),并且只有在出现性能问题时才取消规范化,而这些问题无法通过更好的查询、归档策略或更大的硬件解决

在现代系统中,这可能意味着数千万或数亿条记录

如果您真的关心这一点,请构建一个测试工具,其中记录的数量是您在生产中预期的两倍,并查看应用程序的性能

对于您担心的性能问题,有许多解决方案


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

但花了多少钱将来自Rotate_Photo table,它将是记录总数的.1倍。哦,耶。。但是足够快吗?此查询每秒运行七次?通常,如果在筛选字段上添加索引并优化表,count(*)将足够快。但是,如果您每秒运行几次(您的问题中没有明确说明这一点,因此可能需要添加这一重要事实),那么创建另一个表来存储计数可能是有意义的。您可能还需要考虑将表引擎更改为MyISAM。参考:您是否测量了记录计数/求和所需的时间?您说“计算动态余额”,但我不应该每月运行一次程序,以验证动态计算是否正确。就像生成最终报表之前的电话账单或信用卡使用量一样。