1

これはちょっと変です。次のクエリがあります:

SELECT * , GROUP_CONCAT( x.tag
SEPARATOR ',' ) AS tags
FROM tag AS t, tag AS x, tag_message_rel AS r, message m
INNER JOIN `user` AS u ON m.user_id = u.id
WHERE t.tag
IN (
'kikikiki', 'dsa'
)
AND m.id = r.message_id
AND t.id = r.tag_id
AND x.id = r.tag_id
GROUP BY m.id
HAVING COUNT( * ) >=2
ORDER BY m.created_at DESC
LIMIT 0 , 20

ご覧のとおり、tを使用して参加し、必要なメッセージを検索します。反対側では、xを使用してメッセージのタグを印刷します。私は行を消去します:

AND x.id = r.tag_id

必要なメッセージが表示されますが、タグには、タグテーブル内のすべてのタグがコマで区切られています。そこに行を残すと、それらの2つのタグしか取得できません。Explainを使用すると、次のようになります。

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  u   system  PRIMARY     NULL    NULL    NULL    1   Using temporary; Using filesort
1   SIMPLE  t   range   PRIMARY,tag     tag     252     NULL    2   Using where
1   SIMPLE  x   eq_ref  PRIMARY     PRIMARY     4   verse.t.id  1    
1   SIMPLE  r   ALL     NULL    NULL    NULL    NULL    180     Using where; Using join buffer
1   SIMPLE  m   eq_ref  PRIMARY     PRIMARY     4   verse.r.message_id  1   Using where

今はこれの専門家ではありませんが、問題はクエリを最適化するプロセスでテーブルに再参加することを拒否していることだと思います。

どう思いますか?簡単な修正はありますか?

4

2 に答える 2

1

問題は、テーブルに 2 回参加しようとしていることですがtag、実際にはtag_message_relテーブルに 2 回参加し、それぞれからテーブルのそれぞれの行に参加する必要がありtagます。

「テーブル エイリアス」は、テーブル自体ではなく、テーブル内の行を参照するものと考えてください。このアイデアは、複雑な結合をよりよく理解するのに役立ちました。

そのクエリの書き方は次のとおりです。

SELECT m.*, u.*, GROUP_CONCAT(DISTINCT x.tag) AS tags
FROM message m
 JOIN `user` u ON (u.id = m.user_id)
 JOIN tag_message_rel r1 ON (m.id = r1.message_id)
 JOIN tag t ON (t.id = r1.tag_id)
 JOIN tag_message_rel r2 ON (m.id = r2.message_id)
 JOIN tag x ON (x.id = r2.tag_id)
WHERE t.tag IN ('kikikiki', 'dsa')
GROUP BY m.id
HAVING COUNT(DISTINCT t.tag) = 2
ORDER BY m.created_at DESC
LIMIT 0 , 20;

JOIN構文を一貫して使用する習慣を身に付ける必要があります。混合JOINおよびコンマ形式の結合は、いくつかの微妙な問題を引き起こす可能性があります。

結合の一部を非相関サブクエリにプルする代替クエリを次に示します。そのため、 と の間のデカルト積を回避tし、グループ関数の修飾子xを削除します。DISTINCT

SELECT m.*, u.*, GROUP_CONCAT(x.tag) AS tags
FROM message m
 JOIN `user` u ON (u.id = m.user_id)
 JOIN tag_message_rel r ON (m.id = r.message_id)
 JOIN tag x ON (x.id = r.tag_id)
WHERE m.id = ANY (
    SELECT m2.id 
    FROM message m2 
     JOIN tag_message_rel r2 ON (m2.id = r2.message_id)
     JOIN tag t ON (t.id = r2.tag_id)
    WHERE t.tag IN ('kikikiki', 'dsa') 
    GROUP BY m2.id 
    HAVING COUNT(t.tag) = 2)
GROUP BY m.id
ORDER BY m.created_at DESC
LIMIT 0 , 20;
于 2009-03-22T03:38:15.520 に答える
0

次の理由で、これら2つのタグのみを取得します。

  1. t.tag IN('kikikiki'、'dsa')。2 t.id IN(id-for-kikikiki、id-for-dsa)
  2. t.id = r.tag_id
  3. r.tag_id = x.id
  4. 3と4を組み合わせると、t.id = x.id
  5. すべてを組み合わせて、x.tag IN('kikikiki'、'dsa')

私はあなたが望むのは2番目に参加することだと思いますtag_message_relt最初のものに参加します。x2番目のものに参加します。両方に参加してくださいmessage。あなたが実際に言っていなかったので、これがあなたが望むものであるかどうか完全にはわかりません...

于 2009-03-21T06:32:56.093 に答える