我正在试图弄清楚如何在我的数据库中高效实现标记。
一种方法是有一个文章表(比方说Articles, ArtID int PK, ArtText varchar(max)
)和一个标签表(让我们说Tags, TagID int PK, TagTitle varchar(15)
)。然后我将创建一个连接表来创建文章和标签之间的多对多关系(假设ArticleTags, ArtID int, TagID int (compound primary key)
。
我的第一个问题是,编写查询以查找与给定标记关联的所有文章的最佳方法是什么?如果我想返回组合数据,我知道连接,但如果我只想知道哪些文章行与特定标签相关联,那么最有效的查询是什么。在现实生活中,我需要找到带有多个标签的文章,最好还能找到与特定标签无关的文章。
我的第二个问题是我的Tags表是否应该有一个int PK?使用TagTitle作为主键更有意义吗?
答案 0 :(得分:2)
(1)
(a)具有特定标签的物品:
SELECT columns FROM Articles WHERE EXISTS
(SELECT null FROM ArticleTags at
WHERE at.ArtID = Articles.ArtID AND at.TagID=x)
(b)没有特定标签的物品:
SELECT columns FROM Articles WHERE NOT EXISTS
(SELECT null FROM ArticleTags at
WHERE at.ArtID = Articles.ArtID AND at.TagID=x)
(2)如果您只是获取与文章关联的标签列表,则使用TagTitle会更快,但对于大多数其他可能的操作,代理int
将更快。
答案 1 :(得分:0)
1a)我的第一个问题是,编写查询以查找与给定标记关联的所有文章的最佳方法是什么?
select ArtID -- if only IDs are required
from ArticleTags
where TagID=1 -- or use the text (where tagtitle='x')
select A.*
from ArticleTags T inner join Articles A on A.ArtID = T.ArtID
where T.TagID=1
1b)在现实生活中,我需要找到包含多个标签的文章
-- has tags 1,3 and 8
select T1.ArtID
from ArticleTags T1
inner join ArticleTags T2 on T1.ArtID = T2.ArtID and T2.TagID = 3
inner join ArticleTags T3 on T1.ArtID = T3.ArtID and T3.TagID = 8
where T1.TagID=1
-- or use the text (tagtitle='x') on each filter
在某些情况下,此表单的工作速度更快。可以连接此前一个或前一个来获取文章记录。
select ArtID
from (
select T1.ArtID from ArticleTags T1 where T1.TagID=1
union all
select T2.ArtID from ArticleTags T2 where T2.TagID=3
union all
select T3.ArtID from ArticleTags T3 where T3.TagID=8
) X
group by ArtID
having count(ArtID) = 3
1c)并且找到与特定标签无关的文章会很好。
select A.*
from Articles A
left join ArticleTags T on T.ArtID = A.ArtID and T.TagTitle = 'nomatch'
where T.ArtID is null
2)我的第二个问题是我的Tags表是否应该有一个int PK?使用TagTitle作为主键更有意义吗?
我坚定地说,每个表应该有一个连续的,无意义的整数ID。它减少了存储空间(FK来自其他表),int lookup / range合并总是比varchar快。