MYSQL优化JOINED UNION SELECT查询

时间:2016-04-04 15:48:28

标签: mysql sql join union

我现在已经重复写了几次这个查询(现在是星期一),试图找到最有效的方法来获取我需要的数据但是我不确定我现在是否正确接近它

总结问题;

用户有两组标记(key_termsproject_terms),userstags表之间的每个标记之间都有一个链接表。

我想拉出任何一个表中都有指定标签的用户。 理想情况下,它还包含该用户的“最相关”标记 - 但暂时将其放在一边。

用户

| id | name |
| 1  | dayjo |
| 2  | stackoverflow |

标签

| id | tag  |
| 1  | tag1 |
| 2  | tag2 | 

user_key_term

| user_id | tag_id |
| 1       | 1      |
| 1       | 2      |
| 2       | 1      |

project_key_term

| user_id | tag_id | 
| 1       | 3      |
| 2       | 3      |

我希望能够查询的是命名标记,即如果我搜索“tag1”,则应返回两个用户,但是如果我搜索“tag2”,则只返回用户1。

我的解决方案

我尝试选择用户,并加入标签两次(每个链接表一个),这似乎工作正常但不确定这是最好的方法,并且无法弄清楚如何获得最相关的标签。

SELECT t1.tag, t2.tag as most_relevant_tag, users.* FROM users
LEFT JOIN user_key_term ON user_key_term.user_id = users.id
LEFT JOIN tags t1 ON user_key_term.tag_id = t1.id
LEFT JOIN project_key_term ON project_key_term.user_id = users.id
LEFT JOIN tags t2 ON project_key_term.tag_id = t2.id
WHERE t1.tag IN ('tag1','tag2') OR t2.tag IN ('tag1','tag2')
GROUP BY users.id;

我的下一次尝试是UNION选择,但这个感觉很脏;

SELECT users.*  FROM 
    `users`
    INNER JOIN (
        SELECT project_key_term.user_id, tags.id, tags.tag FROM project_key_term
        JOIN tags ON tags.id = project_key_term.tag_id AND tags.tag IN ('tag1')
        UNION ALL
        SELECT user_key_term.user_id,tags.id, tags.tag  FROM user_key_term
        JOIN tags ON tags.id = user_key_term.tag_id AND tags.tag IN ('tag1')
        ) tags ON tags.user_id = users.id
    WHERE tags.tag IN ('tag1')
    GROUP BY users.id;

但是

我已经尝试在两个查询上运行EXPLAIN以查看哪个最好,但它没有显示对我特别有用的任何内容。特别是因为目前表中的数据不多,可能会有数百/数千个标签。

任何关于“正确”或最佳实践方式的帮助都可以做到这一点!

1 个答案:

答案 0 :(得分:0)

union查询可以简化为:

SELECT users.*  
FROM users
INNER JOIN (
        SELECT user_id,tag_id 
        FROM project_key_term
        UNION ALL
        SELECT user_id,tag_id 
        FROM user_key_term
        ) alltags ON alltags.user_id = users.id
INNER JOIN tags t on t.id = alltags.tag_id
where t.tag IN ('tag1')

编辑:获取最相关的标签

 SELECT score, t.tag, users.* 
 FROM users
 INNER JOIN (select user_id, tag_id, count(*) as score 
             from (SELECT user_id,tag_id 
                   FROM project_key_term
                   UNION ALL
                   SELECT user_id,tag_id
                   FROM user_key_term
                   ) alltags
             group by user_id,tag_id) tagcounts ON tagcounts.user_id = users.id
 INNER JOIN tags t on t.id = tagcounts.tag_id
 where t.tag IN ('tag1','tag2','tag3')
 ORDER BY score DESC