使用 0/NULL 值进行规范化还是可以设计得更好?

Normalisation with 0/NULL values or can it be designed better?

我正在为以下场景在 MySQL 中规划我的数据库 -

我正在尝试建立一个逐场比赛的系统,例如 NBA,其中

 Play event[id, play_type_id, play_outcome_id, points] 

  Substitution event[id, player1_in_id, player2_out_id]  

  Foul event[id, foul_type_id, player_id] 

在主 play_by_play 记分卡中,特定事件应与特定时间和比赛相关联

Play_by_Play[id, match_id, time_id, play_event_id, substitution_event_id, foul_event_id] 

然而,假设在特定的一分钟内,三个事件中只有一个发生 - 三分之二的事件记录中只有一个具有 ID,其他事件记录要么为 0,要么为 NULL。我剩下的问题是这种设计的规范化很好,还是有更好的方法来做到这一点?

我不认为只有一个答案,它在很大程度上取决于您如何使用数据。

一种方法 是让Play_by_Play table 包含对事件的单个引用,从而避免 NULL 和 0 的开销。

Play_by_Play[id, match_id, time_id, event_id]

您可以定义一个通用事件

Event_type [event_type_id, type_name]
Generic_Event[event_id, event_type_id]

所有其他事件类型都可以是此通用事件类型的 1:1 扩展:

Play event[id, event_id, play_type_id, play_outcome_id, points] 
Substitution event[id, event_id, player1_in_id, player2_out_id]  
Foul event[id, event_id, foul_type_id, player_id] 

此设计有利于规范化并允许快速 select 有关事件的信息,无论其类型如何(您的设计为此需要多个连接)。

但是,聚合信息将需要更多的连接(到 table 实际保存事件相关数据的连接)并且 Generic_Event 可能会增加很多,并对性能产生潜在影响。

您的方式有利于更快地聚合信息,因为您只能查询Play_by_Play table。例如:获取一个时间范围内的换人次数和犯规次数。

它也可能更 space 和查询执行效率更高,因为您使用更少 JOIN 并且没有大事件 table。

不清楚您的实际数据库引擎是什么(您同时标记了 MySql 和 SQL 服务器),但是对于 SQL 服务器,有一个功能可以帮助您优化 space 对于 tables 有很多 NULL 值:sparse columns.

如果目标是跟踪事件,则在单个 table 中关注每个事件一行。

play_typefoul_type 混合成一个 type,使用 substitution as anothertype`。

考虑将 "substitution" 分成两个事件:移除玩家和添加玩家。这消除了专为该事件而存在的额外玩家列。 (但如果您想将其称为单个事件,事情就会变得复杂。)

可能需要少量 NULLable 列。