用户 ID 是自然键还是代理键?为什么?

Maximize job database potential with expert discussions and advice.
Post Reply
muskanislam99
Posts: 243
Joined: Sat Dec 28, 2024 5:47 am

用户 ID 是自然键还是代理键?为什么?

Post by muskanislam99 »

WhatsApp 的用户 ID 几乎肯定是代理键 (Surrogate Key)。

为什么是代理键?
代理键是一个由系统生成、内部使用、没有业务含义且通常是不可变的标识符。与此相对,自然键是基于业务数据(如电话号码、身份证号)的标识符。

WhatsApp 选择代理键作为用户 ID,原因如下:

不变性 (Immutability):

问题: 电话号码(最自然的候选键)可能会改变。用户可 丹麦 whatsapp 数据库 能会换号,但希望保留他们的 WhatsApp 账户和所有聊天记录。
代理键优势: 如果 user_id 是一个代理键(例如,一个自增的 BIGINT 或 UUID),那么即使用户的电话号码或其他任何业务属性发生变化,user_id 仍然保持不变。所有依赖 user_id 的关联表(如 Messages、GroupMembers、Payments 等)都不需要更新,大大简化了数据库管理和数据一致性。
数据隐私与安全 (Privacy & Security):

问题: 如果电话号码是主键,它将存在于所有需要引用用户的表中,增加了敏感信息(电话号码)泄露的风险。
代理键优势: user_id 不包含任何个人身份信息。在内部数据库中广泛使用 user_id 可以更好地隔离敏感的电话号码,提高数据安全性。只有在需要时,系统才会通过 user_id 去查找对应的电话号码。
性能 (Performance):

问题: 电话号码通常是字符串类型,并且长度不固定。字符串作为主键会降低数据库索引的效率和查询性能,尤其是在大量 JOIN 操作时。
代理键优势: 代理键通常是整数类型(如 BIGINT),它们占用空间小,比较和排序效率高。数据库处理整数索引的速度远快于字符串索引,这对于 WhatsApp 庞大的用户基数和高并发操作至关重要。
标准化与格式问题 (Standardization & Formatting):

问题: 电话号码的格式多种多样(带空格、破折号、国际区号前缀等),即便标准化为 E.164 格式,字符串比较的复杂性依然存在。
代理键优势: 代理键是系统内部的纯粹数字或 UUID,无需担心外部格式问题,简化了数据处理逻辑。
解耦 (Decoupling):

问题: 将业务属性(如电话号码)作为主键,会使数据库 Schema 与业务规则紧密耦合。如果业务规则发生变化(例如,未来支持邮箱注册),数据库结构可能需要大规模调整。
代理键优势: 代理键将数据库的内部标识与外部业务逻辑解耦。即使 WhatsApp 未来引入新的用户识别方式(如邮箱、用户名),user_id 仍然可以是其唯一的内部标识。
WhatsApp 的实际实践
在 WhatsApp 的数据库中,几乎可以确定存在一个像这样的 Users 表:

SQL

CREATE TABLE Users (
user_id BIGINT PRIMARY KEY, -- 代理主键,由系统生成
phone_number_standardized VARCHAR(20) UNIQUE NOT NULL, -- 标准化后的电话号码,作为唯一业务标识
-- ... 其他用户属性
);
所有其他涉及用户的表,如 Messages、GroupMembers、CallRecords 等,都会使用 user_id 作为外键来引用用户,而不是电话号码。

这种设计是构建可扩展、安全且易于维护的大规模分布式系统的标准范式。
Post Reply