【问题标题】:Optimizing Multilevel MySQL subqueries (folksonomy and taxonomy)优化多级 MySQL 子查询(folksonomy 和 taxonomy)
【发布时间】: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 用于添加更新。

标签: mysql subquery join


【解决方案1】:

据我所知,这是解决方案:

SELECT DISTINCT(`t`.`id`) FROM `post_tags` as `pt`
    left join `tags` as t on `t`.`id` = `pt`.`tag_id`
    where `pt`.`user_id` in(
        SELECT distinct(`pt`.`user_id`) FROM `post_tags` as `pt`
             LEFT JOIN `tags` as `t` on `t`.`id` = `pt`.`tag_id`
              WHERE `pt`.`tag_id` in(
                 SELECT distinct(`tag_id`) FROM `post_tags` 
                 WHERE pt.user_id = 3
            )
    )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-10
    • 1970-01-01
    相关资源
    最近更新 更多