3

一連の記事を参照するテーブルがあり、テーブルにはそれらの記事のタグが含まれています。このような:

tag text
article_id bigint

tag1、tag2、tag3 などの一連のタグを持つすべての article_id を選択したいのですが、記事には tag4、tag5 も添付されている可能性があります。

私はこれがうまくいくことを知っています:

SELECT article_id 
FROM tag WHERE tag='tag1' 
INTERSECT 
SELECT article_id 
FROM tag 
WHERE tag='tag2' 
INTERSECT 
SELECT article_id 
FROM tag 
WHERE tag='tag3'

そして、これもそうです:

SELECT article_id 
FROM tag 
WHERE tag IN ('tag1','tag2','tag3') 
GROUP BY article_id 
HAVING count(*) = 3

しかし、それがこれを行うための最も効率的な方法であるかどうかはわかりません。私も以下で遊んでいますが、現在は動作しません。

SELECT array_agg(tag) as arr,
       article_id 
FROM tag 
GROUP BY article_id 
HAVING arr = {tag1,tag2,tag3}

これは、他の人が遭遇する一般的な問題のように思えました。この場合、INTERSECT が最も効率的なクエリであるかどうか疑問に思っていました。PostgreSQL用です。

4

3 に答える 3

1

articleだけでなく、より多くの列が必要だと思いますarticle_id。ただし、クエリ スタイルはあまり変わりません。

あなたが扱っているのは、関係分割と呼ばれます。そして、この関連する質問で見られるように、この猫の皮をむく方法はかなりたくさんあります- インデックス作成やパフォーマンス テストに関するアドバイスなどがあります。

私の個人的なお気に入り (そしておそらく最速のもの) は次のとおりです。

SELECT a.*
FROM   article a
JOIN   tag x USING (article_id)
JOIN   tag y USING (article_id)
JOIN   tag z USING (article_id)
WHERE  x.tag = 'tag1'
AND    y.tag = 'tag1'
AND    z.tag = 'tag3';

または:

SELECT a.*
FROM   article a
WHERE  EXISTS (
   SELECT *
   FROM   tag x
   JOIN   tag y USING (article_id)
   JOIN   tag z USING (article_id)
   WHERE  x.article_id = a.article_id
   AND    x.tag = 'tag1'
   AND    y.tag = 'tag2'
   AND    z.tag = 'tag3'
   );

@Davidは、3番目のバージョンが機能しない理由をすでに説明しました。ただし、インデックスを使用できず、ここにある他の方法よりも桁違いに遅くなるため、決して使用しないでください。

于 2012-03-12T05:39:59.667 に答える
0

個人的には2番目のオプションが好きです。ただし、PostgreSQLのツールといくつかのテストクエリを使用して、どれが最も効率的かを確認する必要があります。

3番目が記述どおりに機能しない理由は、array_agg()の並べ替え順序を指定する必要があるためです。つまり 、array_agg()をmySQLのgroup_concat()のように機能させる方法です。

于 2012-03-11T23:26:24.973 に答える
0

最後のバリアントでは、配列の等価性には関心がありません。配列の包含に関心がHAVING arrあり、3 つのタグがすべて含まれています。

また、array1 にはarray1 @> array2、PostgreSQL にある array2 が含まれています。

それでも、インデックス作成のおかげで、アーウィンの答えがパフォーマンスの面で勝つと期待しています。

于 2012-03-13T06:51:10.380 に答える