3

現在、アプリケーションで実行するのに最大10秒かかる現在のMySQLクエリがあります。

SELECT tagid, tag FROM tags WHERE tagid IN 
(SELECT DISTINCT tagid FROM news_tags WHERE newsid IN 
(SELECT newsid FROM news_tags WHERE tagid IN (16,32)
GROUP BY newsid HAVING COUNT(newsid)>=2)) 
AND tagid NOT IN (16,32) ORDER BY level, tagid

使用されるテーブルは次のとおりです。

  • テーブルnews_tags、列newsidあり、tagid
  • テーブルtags、列tagid付きtag、、level

tagidクエリの目的は、 1632のタグでタグ付けされた「ニュース」アイテムを検索し、次にこれらのニュースアイテムにもタグ付けされた他のタグを検索して、ユーザーが「ニュース」をさらに絞り込むことができるようにすることです。 "より具体的なタグの組み合わせを持つアイテム。最終的な目標は、テーブルから残りの関連する列tagを取得することです。tagidtags

同等の方法でさまざまな試みを試みましたが、提供されたタグが添付されているニュースアイテムのJOIN残りのすべてを選択できませんでした。tagid

これが私のEXPLAINSQLの結果です。これは、私が見逃している別の速度低下の原因を示している場合に備えています。

id | select_type | table | type |possible_keys | key | key_len | ref | rows | Extra
 1 |PRIMARY|タグ|範囲|PRIMARY| PRIMARY | 4 | NULL | 55|どこを使用するか; filesortの使用
 2 | DEPENDENT SUBQUERY | news_tags | index_subquery | tagid | tagid | 4 | func | 26|インデックスの使用; 場所を使用する
 3 | DEPENDENT SUBQUERY | news_tags | index | tagid | PRIMARY | 8 | NULL | 11|どこを使用するか; インデックスの使用

問題を明確にするために、16または32ではなく、タグ16と32の両方でタグ付けされたニュースアイテムのタグを残したかったのです。混乱してすみません。

4

3 に答える 3

2
SELECT DISTINCT tags.tagid, tags.tag
FROM
       tags                             -- tags from the ...
  JOIN news_tags AS n0 USING (tagid)    -- ... news items tagged with ...
  JOIN news_tags AS n1 USING (newsid)   -- ... tagid = 16 and ...
  JOIN news_tags AS n2 USING (newsid)   -- ... tagid = 32
WHERE
  n1.tagid = 16 AND n2.tagid = 32
  AND tags.tagid NOT IN (16,32)         -- not the tags we already know about
ORDER BY tags.level, tags.tagid
于 2012-04-30T17:33:28.447 に答える
1

編集:私のクエリは、提供されたsql OPに厳密に基づいており、質問のタイトルで尋ねられたようにクエリを高速化しようとしていました。

SELECT DISTINCT t.tagid, t.tag FROM tags AS t
JOIN            news_tags AS nt1 USING (tagid) 
JOIN            news_tags AS nt2 USING (newsid)
WHERE           nt2.tagid IN (16, 32) AND t.tagid NOT IN (16, 32) 
GROUP BY        nt2.newsid HAVING COUNT(nt2.newsid)>=2
ORDER BY        t.level, t.tagid
于 2012-04-30T18:06:28.780 に答える
0

私は最終的に、INステートメントの代わりにJOINSを使用してこの問題を解決する高速クエリを思いつきました。

SELECT tags.tagid,tags.tag FROM tags 
INNER JOIN (SELECT DISTINCT news_tags.tagid FROM news_tags
INNER JOIN (SELECT newsid FROM news_tags WHERE tagid IN (16,32) 
GROUP BY newsid HAVING count(newsid) >= 2) tagged_news 
ON news_tags.newsid = tagged_news.newsid 
WHERE news_tags.tagid NOT IN (16,32)) rem_tags
ON tags.tagid = rem_tags.tagid
ORDER BY level, tagid

これは明らかにeggyalのソリューションほどクリーンでもエレガントでもないので、最終的に彼のソリューションをアプリケーションに採用しました。

問題に最適なSQLステートメントを見つけるためにも、将来のために学ぶためにも、eggyvalのソリューションが上記のSQLステートメントよりも好まれる理由について、より客観的な理由(エレガンス以外)を聞きたいと思います。これまでのすべての助けに感謝します。

于 2012-05-01T10:34:54.130 に答える