
1) 【一句话结论】采用以用户为中心的多表关联设计(用户表、好友表、关注表),通过联合主键优化查询,结合索引和消息队列实现高效查询与实时更新。
2) 【原理/概念讲解】同学们,设计用户关系图谱时,核心是处理“用户-关系-用户”的关联。常见模式是星型架构——以用户表为核心,通过好友表(记录双向好友关系)和关注表(单向关注关系)扩展。比如,用户A关注用户B,在关注表中存A->B的记录。表结构上,用户表用自增ID,关系表用(用户ID1, 用户ID2)作为联合主键(唯一标识关系),避免重复。索引方面,主键自增ID天然有序,关系表的主键索引能加速查找;同时为用户ID字段建索引,支持按用户ID筛选关系。实时更新时,新增好友后,通过消息队列(如Kafka)通知相关表更新,再触发缓存刷新,保证数据一致性。
3) 【对比与适用场景】
| 设计方式 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 单表存储 | 将所有关系存入一张表(如user_relations,字段:user_id1, user_id2, relation_type, created_at) | 数据冗余(如A-B和B-A重复),查询时需去重 | 小型应用,关系简单 | 查询性能差,扩展性弱 |
| 多表关联 | 用户表 + 好友表(双向,user_id1, user_id2)+ 关注表(单向,follower_id, followee_id) | 结构清晰,无冗余,支持复杂查询 | 大型社交应用,关系复杂 | 需处理多表关联查询,索引设计关键 |
4) 【示例】
-- 创建用户表
CREATE TABLE users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 创建好友表(双向,无冗余)
CREATE TABLE friendships (
user_id1 INT NOT NULL,
user_id2 INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id1, user_id2),
FOREIGN KEY (user_id1) REFERENCES users(user_id),
FOREIGN KEY (user_id2) REFERENCES users(user_id)
);
-- 创建关注表(单向)
CREATE TABLE follows (
follower_id INT NOT NULL,
followee_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (follower_id, followee_id),
FOREIGN KEY (follower_id) REFERENCES users(user_id),
FOREIGN KEY (followee_id) REFERENCES users(user_id)
);
-- 插入数据示例
INSERT INTO users (username) VALUES ('Alice'), ('Bob'), ('Charlie');
-- 添加好友(Alice和Bob互加好友)
INSERT INTO friendships (user_id1, user_id2) VALUES (1, 2), (2, 1);
-- Alice关注Charlie
INSERT INTO follows (follower_id, followee_id) VALUES (1, 3);
-- 查询Alice的好友
SELECT u.username FROM users u JOIN friendships f ON u.user_id = f.user_id2 WHERE f.user_id1 = 1;
-- 查询Alice的关注列表
SELECT u.username FROM users u JOIN follows f ON u.user_id = f.followee_id WHERE f.follower_id = 1;
5) 【面试口播版答案】面试官您好,针对社交应用的用户关系图谱设计,我的核心思路是采用以用户为中心的多表关联模式。具体来说,我会设计用户表存储用户基本信息,然后通过好友表(双向关系,用联合主键避免冗余)和关注表(单向关系)来记录连接。索引方面,好友表和关注表的主键(联合主键)天然支持高效查询,同时为用户ID字段建索引,加速按用户ID筛选关系。对于实时更新,比如好友添加,我会通过消息队列(如Kafka)接收新增事件,触发数据库更新后同步缓存,确保查询性能和实时性。这样既能保证数据结构清晰,又能优化查询和实时更新能力。
6) 【追问清单】
7) 【常见坑/雷区】