如何设计一款高效的TAG索引系统
TAG和对象是多对多的关系,一般会建立一张独立的关系表,来处理TAG的增、删、修改,如果要对TAG加上计数,以及组合计数,该如何设计数据库才能高效。
比如有以下TAG:
PHP X 1000个相关
MYSQL x 500个相关
PHP MYSQL x 150个相关
Answers
@小白 的方案基本上已经可以满足需求,我再补充一下。
一、需求分析
大数据量情况下,该系统的设计难点主要有以下几个:
1)每个Tag下的对象数目的即时获取
2)多个Tag下的共有对象数目的即时获取
二、数据库设计
根据需求可以设计数据库model如下:
说明:
1)对象所属的tags用冗余字段obj_tags记录,每条对象记录都做memcache缓存
2)每个Tag下的对象数目用冗余字段obj_num记录,每条Tag记录都做memcache缓存
3)relations表的tag_id字段做索引
4)查询某个Tag下的对象总数目:
SELECT obj_num FROM tags WHERE tag_id = $tag_id
(先查询memcache缓存)
或
5)查询多个Tag下的共有对象总数目:
SELECT COUNT(*) FROM relations a
LEFT JOIN relations b ON(a.obj_id = b.obj_id)
WHERE a.tag_id = $tag1 AND b.tag_id = $tag2
三、系统改进
以上设计在获取多个Tag下的共有对象总数时还是会直接查询数据库,虽然会使用索引,查询速度也不慢,但是大访问量时的磁盘IO消耗依然不可小视。
为此,我们引入Redis作为缓存,可以充分利用其丰富的数据结构。在这里我们使用集合类型来存储Tag下的对象列表,其提供的交集操作可以很优雅地完成多个Tag下的共有对象数目的即时获取。
说明:
1)数据库设计保持不变
2)Redis采用纯内存运行,不做持久化,宕机时从relations表恢复数据
3)获取指定Tag下的对象列表:用SMEMBERS命令
4)获取指定Tag下的对象总数:用SCARD命令
5)获取多个Tag下共有的对象列表:用SINTER命令