如何设计一款高效的TAG索引系统


TAG和对象是多对多的关系,一般会建立一张独立的关系表,来处理TAG的增、删、修改,如果要对TAG加上计数,以及组合计数,该如何设计数据库才能高效。
比如有以下TAG:
PHP X 1000个相关
MYSQL x 500个相关
PHP MYSQL x 150个相关

系统设计 数据库设计

Florens 12 years, 7 months ago

@小白 的方案基本上已经可以满足需求,我再补充一下。

一、需求分析
大数据量情况下,该系统的设计难点主要有以下几个:
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缓存)

   
  SELECT COUNT(*) FROM relations WHERE tag_id = $tag_id
 

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命令

阿伦·艾弗森 answered 12 years, 7 months ago

Your Answer