l46*_*kok 0 mysql database-design primary-key
我很难为我的数据库表在自然 PK 和代理 PK 之间进行选择。
该数据库用于 MOBA 游戏的排名系统。如果我走自然路线,这或多或少是我会做的。
玩家表
- PlayerID Int AI NN UQ
- PlayerName Varchar PK
- ServerName Varchar PK
- Registered date, level, hero etc misc columns
Run Code Online (Sandbox Code Playgroud)
排名表
- PlayerName FK references player
- ServerName FK references player
- RankID Int AI NN UQ
- PlayerRank Int NN UQ
Run Code Online (Sandbox Code Playgroud)
问题是,玩家表中的每一行都由一对 PlayerName 和 ServerName 唯一标识。我认为在这种情况下使用代理键并不是很合适,但我想听听关于此的建议。
这是计算领域的一大哲学争论的一部分。有时它在信息理论家中变得和 Linux 开发人员中的 vi/emacs 一样激烈......
我总是避免使用可能会更改的值作为键或键的一部分,在这种情况下,玩家名称或服务器名称,除非您的系统明确规定这些属性不能更改且必须是唯一的。虽然您可以在某些数据库中使用 ON UPDATE CASCADE 来消除由于需要更新 PK 的值而引起的问题,但这对我来说是不干净的。如果玩家名称必须是唯一的,那么您实际上不需要单独的玩家 ID,因为玩家名称+服务器名称也是玩家表中的候选键。
顺便说一句:你的玩家表对我来说感觉不正确。我会将服务器作为一个单独的实体保存,这样同一个玩家记录可以链接到多个服务器,这样一个在多个地方玩的玩家不必为每个服务器都有不同的记录。就像是:
玩家排名服务器
-------------- ----------------- --------------
PlayerID (PK) <-- PlayerID (FK, PK) ServerName
PlayerName ServerID (FK, PK) --> ServerID (PK)
{更多列} PlayerRank {更多列}
或者
玩家排名服务器
--------------- ------------- --------------
PlayerID (PK) <-- PlayerID (FK) ServerName
PlayerName ServerID (FK) --> ServerID (PK)
{更多列} PlayerRank {更多列}
RankID(PK)
(可能前者因为 PlayerID+ServerID 是候选键,没有额外的 ID 可以节省空间,既没有额外的数据又需要额外的索引)
还有一点:PlayerRank 本身不能是唯一索引,因为您将在每个服务器上拥有至少一名玩家的“排名 1”玩家,因此唯一索引需要超过 ServerID+PlayerRank。