关系型数据库 - 如何决定存储数据还是计算数据?

4
假设您在数据库中有两个表,一个用于高尔夫球员,另一个用于高尔夫球洞,并且还有一个API需要返回球员一生中击中公平路的总数。最佳实践是让API查看每个洞以计算公平路击中次数,还是直接在玩家表中存储击中公平路次数?似乎将这些数据存储在玩家表中基本上是重复数据,因为它已经存在于每个洞中。但是为了计算它,您需要每次都遍历该球员打过的每个洞。
更一般地说,这只是需要在正确的数据设计和性能之间取得平衡的情况吗?
我意识到这可能需要主观答案(如果需要),但我不了解数据库设计足够多,不知道是否有确定的答案来处理此类情况。
3个回答

3
存储派生数据会带来一定的风险或责任。您必须维护派生数据,否则可能会得到错误的答案。这可能会给系统增加复杂性和工作量。在某些情况下,值得在写入时增加复杂性以便在读取时减少复杂性,特别是如果计算很复杂且计算结果可以逐步更新。
在您的示例中,我会尝试通过索引实现良好的性能,而不是存储派生数据。听起来这是一个可以仅通过适当的索引回答的查询,而不需要加载任何物理行。

3
更普遍地说,这只是需要在正确的数据设计和性能之间取得平衡的情况吗?
TL;DR “是的”。
关系模型与性能无关。数据的关系模型是一个正式的理论,它是许多数据模型之一。
数据模型是一个抽象的、自包含的、逻辑定义,它定义了用户与之交互的抽象机器中的对象、运算符等等。
抽象机器没有性能问题,因为它不存在于物理意义上。这就是为什么关系模型不涉及索引等问题的原因。
另一方面,SQL数据库与性能有很大关系。SQL数据库具有物理实现,其性能受核心数、内存量、磁盘空间、配置和主轴转速、并发用户数、索引等等因素的影响。
区别在于逻辑和物理,抽象和具体,以及原则和实践之间的区别。
所以是的,你需要在干净的设计和性能之间取得平衡。每个人都需要。
最好的方法是“先进行干净的逻辑(即关系)设计,然后作为单独的、随后的步骤,将该逻辑设计映射到目标DMBS支持的任何物理结构中。”
如果你必须存储计算结果,最佳做法是让SQL DBMS维护一致性。例如,如果你必须存储(数量*价格)+销售税的结果,则编写CHECK()约束以保证一致性。一些DBMS不支持CHECK()约束。
如果你必须在许多行之间维护总数,请使用物化视图。一些DBMS不支持物化视图。
在最坏的情况下,你只能使用一个人读取的报告来确定是否出现了不一致。这个人采取纠正措施。
在所有情况下,在进行更改之前和之后,测量代表性插入、更新和删除语句的性能。
最佳实践是让API查看每个洞来计算击中球道的数量,还是直接在球员表中存储击中球道的数量?
有很多统计数据。你应该将统计数据存储在一个或多个额外的表中。SQL DBMS不必“查看每个洞”;它们操作集合。
但是为了计算它,您需要每次都遍历该球员打过的每个洞吗?
不,你不需要“遍历每个洞”,至少不是迭代地遍历每个洞,尽管这正是许多前端应用程序框架所做的。你只需要一个单独的SQL查询,例如select count(*) from player_holes where fairway_hit = True;


[1] 数据库系统简介,第七版,C. J. Date,第14页

[2] 同上,第327页。


你让我想起了最近读到的一些内容:“System R 项目的目标是反驳那些声称 Codd 模型由于性能原因不可行的专家的说法。SQL 是由主要兴趣和技能在 DBMS 工程领域而非计算机语言设计的人设计的。” [来源] (http://www.dcs.warwick.ac.uk/~hugh/TTM/HAVING-A-Blunderful-Time.html) - onedaywhen
一些数据库管理系统不支持CHECK()约束,而那些支持的往往会限制它们在属性级别和元组级别上的使用,因为关系和数据库约束的复杂性是任意复杂度的。据说MS Access支持表级检查约束,但实际上它们是逐行检查的,使它们几乎没有用处! - onedaywhen

0

反规范化的主要问题在于需要序列化和复杂的代码来维护重复数据。

我认为你在这里没有这个问题,因为你正在维护一个不会改变的历史数据集,或者至少只会很少改变。

我不认为提供详细统计摘要并在数据更改时维护它们会有害。Oracle 材料化视图可以为您管理此操作,但这不是一种廉价的选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接