tags的数据库设计问题

2012-12-08 22:58:42 +08:00
 talentsnail
每个topic有几个tags,每个tag也能对应多个topic,应该如何设计数据库最合理呢?

想到的一种解决办法是三张表:
1.topic (topic_id,tags)多个tags用某个特殊符号分隔
2.tag (tag_id,tag)
3.topic_tag (topic_id,tag_id)

但是觉得效率会很低,大家的解决方案是怎样?
6649 次点击
所在节点    MySQL
50 条回复
hbc
2012-12-08 23:39:28 +08:00
many2many 啊
best1a
2012-12-08 23:47:12 +08:00
当时弄某个东西就是三张表。。。。
有一点不太理解,都有topic_tag表了,为什么topic中还有tags字段,方便一次取出?
gfreezy
2012-12-08 23:53:19 +08:00
topic_tag(topic_id, tag_id)

select distinct(topic_id) from topic_tag where tag_id = ?

select distinct(tag_id) from topic_tag where topic_id = ?
gfreezy
2012-12-08 23:54:42 +08:00
没看清楚


@best1a 同不理解, left join不就可以了
lqs
2012-12-09 00:06:57 +08:00
@best1a @gfreezy 用冗余字段提高性能,节约若干次disk seek
ElmerZhang
2012-12-09 00:09:09 +08:00
楼主这种方案是比较好的方案,只要索引合理,效率不会有问题。
gfreezy
2012-12-09 00:22:46 +08:00
@lqs 一般情况下只要索引ok,基本都不会有性能问题,除非量真的特别大。直接在topic表里面存tag字符串也有个问题,比如已经有了一个topic,也拿到了他的tags,但是你要给这些tag加链接,你必须至少还要查询一次tag表来拿tag_id(你的tag的URL是根据tag_id拼出来的情况下)。

如果tag可以只存为字符串的话,直接放redis:
* key: "topic:{{topic_id}}" value: tag list
* key: "tag:{{tag_name}}" value: topic_id list
BigZ
2012-12-09 00:37:42 +08:00
简单点,一个字段,tag用逗号分隔
lookhi
2012-12-09 09:01:33 +08:00
@BigZ 我们也是这么干的
lusin
2012-12-09 11:51:01 +08:00
用标点分隔的话
比如 iphone5(苹果,手机)
然后要取出tag为手机的所有数据,应该效率会低吧
lusin
2012-12-09 11:52:57 +08:00
topic1 tag1
topic1 tag2
topic2 tag1
topic2 tag3
这样做表效率是不是高些?
sobigfish
2012-12-09 12:07:47 +08:00
直接写成数组啊, 存在表里
topic1 tag1,tag2
Mutoo
2012-12-09 12:15:26 +08:00
多对多对应关系,范式化后就是三个表。
topic (topicid, ...)
tag (tagid, tag, ...)
topic_tag (topicid, tagid)

这样的好处显而易见。

对topic增删改查tag时只要操作topic_tag表
对tag改名,只需要改tag表
删除tag,只需要删除tag表和topic_tag对应项
统计也很方便
...
atom
2012-12-09 21:16:31 +08:00
楼主的方案就是标准范式,保证一致性,缺点是查询慢。
其它用分隔符只存一张表的是反范式方案,优点是查询快,缺点是一致性比较痛苦。


但吃过一致性的亏后,我会倾向于这样的方案:
1.用标准范式保证一致性;
2.增加缓存层保存热数据,里面的数据已做好关联,便于展现层或业务层直接拿来使用。
3.最上层会有个切换开关(读缓存还是读DB),80%的情况下使用cache数据,做到best-effort,强调可用性,但数据可能不准确。


以下是无责任引用
-----------------------------------------
• 事务处理型:对于这种类型的应用程序,你的用户更关注数据的增查改删(CRUD,Creating/Reading/Updating/Deleting)。这种类型官方称之为 “OLTP”。
• 分析型:对于这种类型的应用程序,你的用户更关注数据分析、报表、趋势预测等功能。这一类的数据库的“插入” 和“更新”操作相对来说是比较少的。用户的主要目的是更加快速地查询、分析数据。这种类型官方称之为 “OLAP”。
换句话说,如果你认为插入、更新、删除数据这些操作在你的程序中更为突出的话,那就设计一个规范化的表,否则的话就去创建一个扁平的、不规范化的数据库结构。
isy
2012-12-09 22:07:14 +08:00
汗,这就是基本多对多的问题。像楼主这样设计没错?用逗号分割存成一个字段的做法太不靠谱了。
zhangtao
2012-12-10 00:15:02 +08:00
想法同@Mutoo ,至于特殊符号分隔还是算了吧,非主流做法
ipconfiger
2012-12-10 00:46:49 +08:00
标准范式查询慢?是SQL优化没做好吧。
AntiGameZ
2012-12-10 02:00:51 +08:00
@isy tags字段的冗余,对减少join次数,提升查询速度来说,在大数据量的时候,意义很大。这样做唯一的问题是,如果有奇葩需求希望修改tagName,需要逐个去修改对应topic tags冗余字段的内容。不过完全可以延迟慢慢去做。
napoleonu
2012-12-10 09:08:42 +08:00
LZ方案很好,如果 1.topic (topic_id,tags) 里面的tags是一段包含tags id的json就更好了,让写分散读压力。
88250
2012-12-10 09:28:03 +08:00
目前和楼主的设计一样,没有发现性能问题。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/54442

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX