如果一行由两列或更多列唯一标识,则使用代理或自然 PK?

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 唯一标识。我认为在这种情况下使用代理键并不是很合适,但我想听听关于此的建议。

Dav*_*ett 5

这是计算领域的一大哲学争论的一部分。有时它在信息理论家中变得和 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。