用户关系链是社交App的核心资产。关注、好友、粉丝、屏蔽,这些关系数据的设计直接影响用户体验和系统性能。什么时候用MySQL?什么时候需要图数据库?这篇文章帮你理清决策逻辑。
一、关系链的业务场景
1.1 常见关系类型
| 关系类型 | 说明 | 特点 |
|---|---|---|
| 单向关注 | A关注B,B不一定关注A | 微博模式 |
| 双向好友 | A和B互为好友 | 微信模式 |
| 粉丝关系 | 单向关注的特殊命名 | 博主模式 |
| 黑名单/屏蔽 | 单向阻止 | 负向关系 |
| 分组关系 | 好友分到不同组 | 朋友圈分组可见 |
1.2 核心查询场景
| 查询 | 说明 | 频率 |
|---|---|---|
| 我关注了谁 | A的following列表 | 高 |
| 谁关注了我 | A的followers列表 | 高 |
| 我和TA是什么关系 | A是否关注B | 极高 |
| 共同关注 | A和B都关注了谁 | 中 |
| 二度关系 | 我关注的人关注了谁 | 低 |
| 好友推荐 | 可能认识的人 | 中 |
二、MySQL方案:适合大多数场景
2.1 表结构设计
基础方案:关系表
CREATE TABLE user_relation (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL COMMENT '用户ID',
target_id BIGINT NOT NULL COMMENT '目标用户ID',
relation_type TINYINT NOT NULL COMMENT '关系类型:1-关注 2-好友 3-屏蔽',
status TINYINT DEFAULT 1 COMMENT '状态:1-正常 0-删除',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_target (user_id, target_id),
INDEX idx_target_user (target_id, user_id)
) ENGINE=InnoDB;
优化方案:分表存储
-- 关注表(我关注的人)
CREATE TABLE user_following (
user_id BIGINT NOT NULL,
target_id BIGINT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, target_id),
INDEX idx_target (target_id)
);
-- 粉丝表(关注我的人)
CREATE TABLE user_follower (
user_id BIGINT NOT NULL,
target_id BIGINT NOT NULL COMMENT '粉丝ID',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, target_id),
INDEX idx_target (target_id)
);
2.2 查询优化
场景1:查询关注列表
-- 查询A关注的人
SELECT target_id FROM user_following
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT 20;
场景2:查询粉丝列表
-- 查询A的粉丝
SELECT target_id FROM user_follower
WHERE user_id = ?
ORDER BY created_at DESC
LIMIT 20;
场景3:判断A是否关注B
-- 高频查询,走主键索引,性能极快
SELECT 1 FROM user_following
WHERE user_id = ? AND target_id = ?;
场景4:查询共同关注
SELECT a.target_id
FROM user_following a
INNER JOIN user_following b ON a.target_id = b.target_id
WHERE a.user_id = ? AND b.user_id = ?;
2.3 MySQL方案的适用范围
| 指标 | MySQL表现 |
|---|---|
| 单用户关系数 | <10000条,无压力 |
| 查询「是否关注」 | 极快(主键查询) |
| 查询关注列表 | 快(索引覆盖) |
| 查询共同关注 | 较慢(JOIN操作) |
| 查询二度关系 | 很慢(多层JOIN) |
| 关系链分析 | 不适合 |
结论: 用户关系数<1万、查询场景简单时,MySQL足够用。
三、什么时候需要图数据库
3.1 图数据库的优势
图数据库天生适合处理「关系」:
| 特性 | MySQL | 图数据库 |
|---|---|---|
| 数据模型 | 表 → 行 | 节点 → 边 |
| 关系查询 | JOIN,多层JOIN性能差 | 遍历,原生支持 |
| 路径查询 | 复杂SQL,性能差 | 简单查询,性能好 |
| 实时推荐 | 不擅长 | 擅长 |
3.2 什么时候该用图数据库
判断标准: 是否需要以下场景?
1、关系查询(朋友的朋友)
是 → 考虑图数据库
2、实时好友推荐
是 → 考虑图数据库
3、关系链分析(影响力计算、社区发现)
是 → 必须图数据库
4、共同好友查询频繁
是 → 考虑图数据库
5、用户关系数>10万
是 → 考虑图数据库
3.3 主流图数据库对比
| 数据库 | 特点 | 适用场景 |
|---|---|---|
| Neo4j | 成熟稳定,社区活跃,Cypher查询语言 | 企业级应用 |
| JanusGraph | 开源,可扩展,基于HBase/Cassandra | 大规模图数据 |
| TigerGraph | 高性能,分布式 | 实时分析 |
| Nebula Graph | 国产开源,分布式,高性能 | 大规模社交网络 |
| ArangoDB | 多模型(文档+图) | 灵活需求 |
四、图数据库实战:Neo4j示例
4.1 数据模型
(User)-[:FOLLOWS]->(User)
4.2 创建关系
// 创建用户节点
CREATE (u1:User {id: 1, name: 'Alice'})
CREATE (u2:User {id: 2, name: 'Bob'})
CREATE (u3:User {id: 3, name: 'Charlie'})
// 创建关注关系
MATCH (u1:User {id: 1}), (u2:User {id: 2})
CREATE (u1)-[:FOLLOWS]->(u2)
4.3 查询示例
查询A关注的人:
MATCH (u:User {id: 1})-[:FOLLOWS]->(target)
RETURN target.id, target.name
查询共同关注:
MATCH (u1:User {id: 1})-[:FOLLOWS]->(common)<-[:FOLLOWS]-(u2:User {id: 2})
RETURN common.id, common.name
查询二度关系(朋友的朋友):
MATCH (u:User {id: 1})-[:FOLLOWS]->()-[:FOLLOWS]->(fof)
WHERE NOT (u)-[:FOLLOWS]->(fof)
RETURN fof.id, fof.name, count(*) AS mutual_friends
ORDER BY mutual_friends DESC
LIMIT 10
好友推荐(基于共同好友数):
MATCH (u:User {id: 1})-[:FOLLOWS]->()-[:FOLLOWS]->(recommend)
WHERE NOT (u)-[:FOLLOWS]->(recommend)
RETURN recommend.id, recommend.name, count(*) AS score
ORDER BY score DESC
LIMIT 10
五、混合方案:MySQL + 图数据库
5.1 架构设计
写入流程:
用户A关注B
│
├── 写入MySQL(主数据源)
│
└── 同步到图数据库(异步)
查询流程:
├── 简单查询(关注列表、是否关注)→ MySQL
└── 复杂查询(推荐、共同好友)→ 图数据库
5.2 数据同步方案
方案1:双写
写入时同时写MySQL和图数据库
优势:实时性好
劣势:一致性难保证,任一失败需要补偿
方案2:消息队列异步同步
写入MySQL → 发送消息到MQ → 消费者写入图数据库
优势:解耦,可靠
劣势:有一定延迟
方案3:CDC同步
MySQL binlog → Debezium → 图数据库
优势:对业务无侵入
劣势:技术复杂度高
六、性能对比实测
测试环境:
· 用户数:100万
· 平均关注数:200
· 最大关注数:5000
查询:「共同关注」
| 方案 | 耗时 |
|---|---|
| MySQL(JOIN) | 500ms |
| MySQL(子查询) | 300ms |
| Neo4j | 50ms |
| Nebula Graph | 30ms |
查询:「好友推荐」(二度关系)
| 方案 | 耗时 |
|---|---|
| MySQL | 2000ms+ |
| Neo4j | 100ms |
| Nebula Graph | 50ms |
七、选型决策总结
你的需求场景是?
1、简单社交(<1万关系/用户)
MySQL足够,没必要上图数据库
2、中等规模(1万-10万关系/用户)
> 需要推荐功能 → MySQL + 图数据库
> 不需要推荐 → MySQL
3、大规模社交(>10万关系/用户)
MySQL + 图数据库(混合方案)
4、关系链分析需求
必须图数据库
下篇预告: 《社交App的离线消息、消息漫游、多端同步设计》——用户体验的关键细节,一个都不能少。
持续输出社交App开发实战经验,关注我,一起成长。