2011-01-18 12 views
0

私のデータベースに効率的にタグを実装する方法を理解しようとしています。多対多のフィルタリングクエリのヘルプ

1つのアプローチは、記事表(Articles, ArtID int PK, ArtText varchar(max)としましょう)とタグの表(Tags, TagID int PK, TagTitle varchar(15)としましょう)を持つことです。そして、記事とタグの多対多の関係を作成するための結合表を作成します(ArticleTags, ArtID int, TagID int (compound primary key)としましょう)。

私の最初の質問は、関連するすべての記事を検索するための最良の方法です特定のタグと関連付けられている記事の行を知りたいのであれば、最も効率的なクエリは何ですか?実際の生活では、

私の2番目の質問は、自分のタグテーブルにint PKがあるべきかどうかについてです。使用するのがより理にかなっていますか? TagTitleを主キーとして使用しますか?

0特定のタグ付き

答えて

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)私の2番目の質問は、自分のタグテーブルがint PKを持つべきかどうかです。 TagTitleを主キーとして使用する方が理にかなっていますか?

キャンプには、各テーブルが意味のない連続した整数IDを持つようにしっかりしています。ストレージのスペース(他のテーブルからのFK)を削減し、intルックアップ/レンジマージはvarcharよりも常に高速です。

+0

1cでは 'NOT EXISTS'を使いますhttp://sqlinthewild.co.za/index.php/2010/03/23/left-outer-join-vs-not-exists/なぜあなたは' UNION ALL 「1bでも?これは 'IN(1,3,8)'ではるかに単純なようです。 –

+0

これはちょっとしたものです。データ配信によっては、他のものよりも速いものが常にあるとは限りません。 NOT EXISTSはおそらく簡潔に読むのが簡単でしょう – RichardTheKiwi

+0

誰かが「SELECT a.ArtID、... FROM記事からINNER JOIN ArticleTags on a.ArtID = at.ArtID INNER JOINタグt ON at.TagID = t.TagID WHERE t.TagTitle = 'tag''? –

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が高速になります。

+0

ありがとうございますが、実際これが最も効率的な方法ですか? Articlesテーブルの各行ごとに、このアプローチではArticleTagsテーブルをスキャンする必要があります。 –

+0

自分自身を試し、クエリの実行計画を見てください。 ArticleTags.TagIDとArticleTags.ArtIDのインデックスがある限り、SQL Serverの実際の計画は非常に効率的です。書き込み効率よりも読み取り効率が重要な場合は、必ずこれらのフィールドをクラスタード・インデックスに入れてください。 – richardtallent