我目前有当前的MySQL查询在我的应用程序中运行最多需要10秒:
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
16 和 32 标记的"新闻"项,然后查找这些新闻项也已标记的其他标签,以便允许用户使用更具体的标记组合进一步缩小"新闻"项的范围。最终目标是从tags
表中获取剩余的相关tag
和tagid
列。
我已经尝试了等效JOIN
的不同尝试,但未能选择附加了所提供标签的新闻项目上所有剩余tagid
。
这是我EXPLAIN
的SQL结果,以防它们指出我缺少的另一个缓慢原因:
id|select_type |表 |type |possible_keys|键 |key_len|ref |rows|额外 1|主要 |标签 |范围 |主要 |主要| 4|空| 55|使用地点;使用文件排序 2|依赖子查询|news_tags|index_subquery|塔吉德 |塔吉德 | 4|函数| 26|使用索引;使用位置 3|依赖子查询|news_tags|索引 |标记 |主要| 8|空| 11|使用地点;使用索引
只是为了澄清这个问题:我希望为同时标记 16 和 32 的新闻项目保留标签,而不是 16 或 32。很抱歉有任何困惑。
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
编辑:我的查询严格基于提供的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
我最终提出了一个快速查询,使用 JOIN 而不是 IN 语句解决了这个问题:
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 的解决方案那样干净或优雅,所以我最终在我的应用程序中采用了他的解决方案。
我很想听到更多客观的原因(除了优雅(,为什么 eggyval 的解决方案比上面的 SQL 语句更可取,既能为问题找到最佳的 SQL 语句,也可以为将来学习。感谢到目前为止的所有帮助。