【发布时间】:2011-01-22 11:30:48
【问题描述】:
我正在阅读 Nitin Borwankar 的精彩 tagging article,他让我开始思考使用两个表实现不同级别搜索的方法。
tags {
id,
tag
}
post_tags {
id
user_id
post_id
tag_id
}
我从T(U(i)) 的简单示例开始,这意味着所有用户的所有标签都有一个项目i。我可以使用以下 SQL 来做到这一点:
/* get all tags from the users found */
SELECT t.*, vt.* FROM verse_tags as vt
LEFT JOIN tags as t ON t.id = vt.tag_id
WHERE user_id in
(
/* Get all user_ids that have taged this item */
SELECT user_id FROM verse_tags WHERE verse_id = 26046 GROUP BY user_id
)
GROUP BY t.id
然后我开始了一个稍微困难的 +1 级深度查询。 T(U(T(u))) 这是用户的标签,使用标签如用户#。
/* Then get the tags of the user with tags like the user 3 */
SELECT t.id FROM post_tags as pt
LEFT JOIN tags as t ON t.id = pt.tag_id
WHERE user_id in
(
/* Then get users with these tags */
SELECT pt.user_id FROM post_tags as pt
LEFT JOIN tags as t on t.id = pt.tag_id
WHERE tag_id in
(
/* get tags of user */
SELECT t.id FROM post_tags as pt
LEFT JOIN tags as t ON t.id = pt.tag_id
WHERE pt.user_id = 3
GROUP BY t.id
)
GROUP BY user_id
)
GROUP BY t.id
但是,由于我通常在查询中使用 JOIN,因此我不确定如何优化这样的事情,或者在使用子查询时需要避免哪些设计缺陷。我什至读过应该使用 JOIN,但我不知道如何使用上述查询来完成。
如何优化这些查询?
更新
1) 将 GROUP BY 替换为 SELECT DISTINCT。 (0.74 秒)
2) 将WHERE in 替换为WHERE exists。 (0.40 秒)
3) 添加索引(哎呀!)(0.09 秒)
4) 返回WHERE in(0.08 秒)
EXPLAIN SELECT DISTINCT tag_id FROM post_tags WHERE user_id in
(
SELECT DISTINCT user_id FROM post_tags WHERE tag_id in
(
SELECT DISTINCT tag_id FROM post_tags WHERE user_id = 3
)
)
运行 EXPLAIN 给了我这些结果:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY post_tags index NULL tag_id 4 NULL 14 Using where
2 DEPENDENT SUBQUERY post_tags index_subquery user_id user_id 4 func 1 Using where
3 DEPENDENT SUBQUERY post_tags index_subquery user_id,tag_id tag_id 4 func 1 Using where
【问题讨论】:
-
不清楚,为什么您的子选择中需要
GROUP BY子句:您没有使用任何聚合函数或HAVING子句。所以它们可以简单地用SELECT distinct子句替换,或者更好地将连接放在SELECT clause中:WHERE exists (SELECT user_id FROM verse_tags vt2 WHERE verse_id = 26046 AND vt.user_id = vt2.user_id) -
谢谢,
SELECT DISTINCT可以很好地替代GROUP BY。但是,由于我不理解您,您能否将评论的第二部分扩展为答案。 -
好吧,我不知道“存在”是什么,但是当我用谷歌搜索它时,我发现了一个解释它的页面。将查询时间减半(尽管只有几条记录,所以这可能很重要)。
-
如果您需要更多调优,请同时提供您的
EXPLAIN查询的输出(语法参见手册)。也许你错过了一些索引。 -
+1 用于添加更新。