我想知道实现标签系统的最佳方法是什么,就像SO上使用的那样。我在想这个,但是我无法提出一个好的可扩展解决方案。
我当时在考虑一种基本的3表解决方案:具有一个tags
表,一个articles
表和一个tag_to_articles
表。
这是解决此问题的最佳解决方案,还是有替代方案?使用这种方法,表的时间将变得非常大,我认为对于搜索而言,效率不是很高。另一方面,快速执行查询并不重要。
最佳答案
我相信您会在此博客文章中找到有趣的地方:Tags: Database schemas
“MySQLicious”解决方案
在此解决方案中,该模式只有一个表,已对其进行了非规范化。该类型称为“MySQLicious解决方案”,因为MySQLicious将del.icio.us数据导入具有此结构的表中。
交叉点(AND)
查询“search + webservice + semweb”:
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags LIKE "%semweb%"
联盟(OR)
查询“search | webservice | semweb”:
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
OR tags LIKE "%webservice%"
OR tags LIKE "%semweb%"
减号
查询“search + webservice-semweb”
SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags NOT LIKE "%semweb%"
“天窗”解决方案
Scuttle将其数据组织在两个表中。该表“scCategories”是“tag”表,并且具有“bookmark”表的外键。
交叉点(AND)
查询“bookmark + webservice + semweb”:
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
HAVING COUNT( b.bId )=3
首先,搜索所有书签标签组合,其中标签为“书签”,“webservice”或“semweb”(c.category IN(“书签”,“webservice”,“semweb”)),然后仅搜索已将所有要搜索的三个标签都考虑在内(HAVING COUNT(b.bId)= 3)。
联盟(OR)
查询“书签| webservice | semweb”:
只需省略HAVING子句,您便拥有并集:
SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
减号(排除)
查询“bookmark + webservice-semweb”,即:书签和webservice,而不是semweb。
SELECT b. *
FROM scBookmarks b, scCategories c
WHERE b.bId = c.bId
AND (c.category IN ('bookmark', 'webservice'))
AND b.bId NOT
IN (SELECT b.bId FROM scBookmarks b, scCategories c WHERE b.bId = c.bId AND c.category = 'semweb')
GROUP BY b.bId
HAVING COUNT( b.bId ) =2
如果没有HAVING COUNT,则会导致查询“bookmark | webservice-semweb”。
“毒性”解决方案
Toxi提出了一个三表结构。通过表格“tagmap”,书签和标签是n-m相关的。每个标签可以与不同的书签一起使用,反之亦然。这个DB模式也被wordpress使用。
查询与“快捷方式”解决方案中的查询完全相同。
交叉点(AND)
查询“bookmark + webservice + semweb”
SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
HAVING COUNT( b.id )=3
联盟(OR)
查询“书签| webservice | semweb”
SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
减号(排除)
查询“bookmark + webservice-semweb”,即:书签和webservice,而不是semweb。
SELECT b. *
FROM bookmark b, tagmap bt, tag t
WHERE b.id = bt.bookmark_id
AND bt.tag_id = t.tag_id
AND (t.name IN ('Programming', 'Algorithms'))
AND b.id NOT IN (SELECT b.id FROM bookmark b, tagmap bt, tag t WHERE b.id = bt.bookmark_id AND bt.tag_id = t.tag_id AND t.name = 'Python')
GROUP BY b.id
HAVING COUNT( b.id ) =2
如果没有HAVING COUNT,则会导致查询“bookmark | webservice-semweb”。