You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

举重训练追踪数据库设计方案选型咨询:双表vs三表架构

Hey,针对你这个举重训练追踪数据库的选型问题,我刚好做过类似的健身APP数据设计,来给你唠唠两个方案的优劣势和我的建议:

举重训练追踪数据库选型建议

方案细节复盘与优劣势分析

方案A:双表结构

  • 核心表:
    • Exercise:存储动作基础信息(ID、Name等)
    • Set:存储每组训练数据(ID、Set_Number、Date、FK_Exercise)
  • 关系:ExerciseSet 为一对多(一个动作对应多组训练)
  • 优势:表数量少,初期开发、维护成本低,单组数据查询时关联逻辑简单
  • 潜在短板:
    • Date字段冗余:同一日期同一动作的多组训练会重复存储日期值,不符合数据库设计的冗余最小化原则
    • 缺乏聚合层:如果后续需要统计「某一天某动作的总组数/总训练量」这类聚合数据,必须按Date+FK_Exercise分组查询,数据量变大后效率会明显下降
    • 逻辑贴合度弱:实际训练中,我们是先完成「某一天针对某个动作的一次训练单元」,再在这个单元下做N组,而不是每组单独绑定动作和日期,方案A的结构和这个真实流程脱节

方案B:三表结构

  • 核心表:
    • Exercise:存储动作基础信息(ID、Name等)
    • Session:存储单次训练单元信息(ID、Date、FK_Exercise)
    • Set:存储每组训练数据(ID、Set_Number、FK_Session)
  • 关系:Exercise → 一对多 → Session(一个动作对应多次训练单元),Session → 一对多 → Set(一个训练单元对应多组训练)
  • 优势:
    • 无冗余字段:Date只存在于Session表,完全符合第三范式,避免数据冗余和不一致风险
    • 逻辑贴合真实场景:Session完美对应「某一天某动作的单次训练」,组次归属于训练单元,业务逻辑更清晰
    • 扩展性极强:如果后续要给训练单元加属性(比如训练状态、备注、当时的体重),直接在Session表加字段即可,不需要改动Set
  • 潜在小成本:初期多维护一张表,查询时多一层关联,但这个开发成本几乎可以忽略

我的选型建议

如果你的系统只是初期简单追踪组次,数据量极小,方案A完全能满足需求,快速上线没问题。但如果考虑到长期迭代和扩展性,我强烈推荐方案B,原因如下:

  1. 聚合查询更高效:比如统计「2024年10月硬拉总组数」,方案B的查询逻辑更清晰,数据量变大后性能优势会更明显
    • 方案A查询示例:
      SELECT COUNT(*) FROM `Set` 
      JOIN `Exercise` ON `Set`.FK_Exercise = `Exercise`.ID 
      WHERE `Exercise`.Name = '硬拉' AND `Date` BETWEEN '2024-10-01' AND '2024-10-31'
      
    • 方案B查询示例:
      SELECT COUNT(`Set`.ID) FROM `Set` 
      JOIN `Session` ON `Set`.FK_Session = `Session`.ID 
      JOIN `Exercise` ON `Session`.FK_Exercise = `Exercise`.ID 
      WHERE `Exercise`.Name = '硬拉' AND `Session`.`Date` BETWEEN '2024-10-01' AND '2024-10-31'
      
  2. 后续扩展更顺畅:比如要给某次训练加备注(「今天状态差,重量减了10kg」),方案B直接在SessionNote字段就行;方案A要么在Set加冗余字段,要么得额外加表,反而更麻烦
  3. 数据一致性更高:方案A中如果某组的Date填错,会导致统计错误;方案B中Date只存在于Session,修改一次就能保证该训练下所有组次的日期一致

内容的提问来源于stack exchange,提问作者pumuckl

火山引擎 最新活动