需求:用户A添加用户B为好友后,A和B即互为好友。
这里只考虑使用数据库实现的方案,以mysql为例。
存在用户表 users,有字段 user_id,如何设计朋友关系表?
CREATE TABLE `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
方案1
CREATE TABLE `user_relation` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`friend_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`,`friend_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
每次用户A添加用户B为好友后,即在数据库中添加两条记录,通过唯一性约束来保证朋友关系不重复。
user_id: 10001, friend_id: 10002
user_id: 10002, friend_id: 10001获取用户A的朋友时 SQL
SELECT friend_id FROM user_relation WHERE user_id = 10001;
优点:存取逻辑比较简单
缺点:user_relation 表中存在冗余的数据
方案2
CREATE TABLE `user_relation` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`friend_id` int(11) DEFAULT NULL,
`sorted_key` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`,`friend_id`),
KEY `sorted_uniq_key` (`sorted_key`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
每次用户A添加用户B为好友后,即在数据库中添加一条记录:
user_id: 10001, friend_id: 10002, sorted_key: 10001-10002
其中 sorted_key 是 (user_id, friend_id) 升序排列后的拼接,通过这个值来做数据库唯一性校验。
获取用户A的朋友时 SQL
SELECT friend_id FROM user_relation WHERE user_id = 10001;
SELECT user_id FROM user_relation WHERE friend_id = 10001;
或
SELECT friend_id as user_id FROM user_relation WHERE user_id = 10001
UNION
SELECT user_id FROM user_relation WHERE friend_id = 10001;
优点:user_relation 表中没有冗余的数据
缺点:获取逻辑比较复杂。唯一性校验也要多占一个字段的空间。