强制 mySQL 加入表(执行我需要的未优化查询)

发布于 2024-07-15 17:38:11 字数 1205 浏览 2 评论 0原文

这有点奇怪。 我有下一个查询:

SELECT * , GROUP_CONCAT( x.tag
SEPARATOR ',' ) AS tags
FROM tag AS t, tag AS x, tag_message_rel AS r, message m
INNER JOIN `user` AS u ON m.user_id = u.id
WHERE t.tag
IN (
'kikikiki', 'dsa'
)
AND m.id = r.message_id
AND t.id = r.tag_id
AND x.id = r.tag_id
GROUP BY m.id
HAVING COUNT( * ) >=2
ORDER BY m.created_at DESC
LIMIT 0 , 20

如您所见,我使用 t 来加入查找我想要的消息,在另一边我使用 x 来打印消息的标签。 我删除了该行:

AND x.id = r.tag_id

我将收到我想要的消息,但标签将包含标签表中的所有标签,并以逗号分隔。 如果我把这条线留在那里,我只会得到那两个标签。 如果我使用解释,我得到:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  u   system  PRIMARY     NULL    NULL    NULL    1   Using temporary; Using filesort
1   SIMPLE  t   range   PRIMARY,tag     tag     252     NULL    2   Using where
1   SIMPLE  x   eq_ref  PRIMARY     PRIMARY     4   verse.t.id  1    
1   SIMPLE  r   ALL     NULL    NULL    NULL    NULL    180     Using where; Using join buffer
1   SIMPLE  m   eq_ref  PRIMARY     PRIMARY     4   verse.r.message_id  1   Using where

现在我不是这方面的专家,但我认为问题在于它在优化查询的过程中拒绝重新加入表。

你怎么认为? 有什么快速解决办法吗?

This is kinda weird. I have the next query:

SELECT * , GROUP_CONCAT( x.tag
SEPARATOR ',' ) AS tags
FROM tag AS t, tag AS x, tag_message_rel AS r, message m
INNER JOIN `user` AS u ON m.user_id = u.id
WHERE t.tag
IN (
'kikikiki', 'dsa'
)
AND m.id = r.message_id
AND t.id = r.tag_id
AND x.id = r.tag_id
GROUP BY m.id
HAVING COUNT( * ) >=2
ORDER BY m.created_at DESC
LIMIT 0 , 20

As you can see i use t to join find the messages that i want, on the other side i use x to print the tags of a message. I i erase the line:

AND x.id = r.tag_id

I will get the messages that i want, but tags will have ALL the tags in the tags table separated by coma. If i leave the line there, i will only get those 2 tags.
If i use explain i get:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  u   system  PRIMARY     NULL    NULL    NULL    1   Using temporary; Using filesort
1   SIMPLE  t   range   PRIMARY,tag     tag     252     NULL    2   Using where
1   SIMPLE  x   eq_ref  PRIMARY     PRIMARY     4   verse.t.id  1    
1   SIMPLE  r   ALL     NULL    NULL    NULL    NULL    180     Using where; Using join buffer
1   SIMPLE  m   eq_ref  PRIMARY     PRIMARY     4   verse.r.message_id  1   Using where

Now im no expert in this, but i think the problem is that it is refusing to re-join a table in the process of optimizing the query.

What do you think? Any quick fix?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

穿透光 2024-07-22 17:38:11

问题是您尝试连接到 tag 表两次,但您确实需要连接到 tag_message_rel 表两次,并从每个表连接到相应的行在 tag 表中。

将“表别名”视为引用表中的行,而不是表本身。 这个想法帮助我更好地理解复杂的连接。

以下是我编写该查询的方式:

SELECT m.*, u.*, GROUP_CONCAT(DISTINCT x.tag) AS tags
FROM message m
 JOIN `user` u ON (u.id = m.user_id)
 JOIN tag_message_rel r1 ON (m.id = r1.message_id)
 JOIN tag t ON (t.id = r1.tag_id)
 JOIN tag_message_rel r2 ON (m.id = r2.message_id)
 JOIN tag x ON (x.id = r2.tag_id)
WHERE t.tag IN ('kikikiki', 'dsa')
GROUP BY m.id
HAVING COUNT(DISTINCT t.tag) = 2
ORDER BY m.created_at DESC
LIMIT 0 , 20;

您应该养成一致使用 JOIN 语法的习惯。 混合使用 JOIN 和逗号式连接可能会导致一些微妙的问题。

这是一个替代查询,它将一些联接拉入不相关的子查询中,因此您可以避免 tx 之间的笛卡尔积,并消除 DISTINCT组函数中的 修饰符。

SELECT m.*, u.*, GROUP_CONCAT(x.tag) AS tags
FROM message m
 JOIN `user` u ON (u.id = m.user_id)
 JOIN tag_message_rel r ON (m.id = r.message_id)
 JOIN tag x ON (x.id = r.tag_id)
WHERE m.id = ANY (
    SELECT m2.id 
    FROM message m2 
     JOIN tag_message_rel r2 ON (m2.id = r2.message_id)
     JOIN tag t ON (t.id = r2.tag_id)
    WHERE t.tag IN ('kikikiki', 'dsa') 
    GROUP BY m2.id 
    HAVING COUNT(t.tag) = 2)
GROUP BY m.id
ORDER BY m.created_at DESC
LIMIT 0 , 20;

The problem is that you are trying to join to the tag table twice, but you really need to join to the tag_message_rel table twice, and from each of these to the respective row in the tag table.

Think of "table aliases" as referring to a row in a table, not the table itself. That idea helped me to understand complex joins a lot better.

Here's how I'd write that query:

SELECT m.*, u.*, GROUP_CONCAT(DISTINCT x.tag) AS tags
FROM message m
 JOIN `user` u ON (u.id = m.user_id)
 JOIN tag_message_rel r1 ON (m.id = r1.message_id)
 JOIN tag t ON (t.id = r1.tag_id)
 JOIN tag_message_rel r2 ON (m.id = r2.message_id)
 JOIN tag x ON (x.id = r2.tag_id)
WHERE t.tag IN ('kikikiki', 'dsa')
GROUP BY m.id
HAVING COUNT(DISTINCT t.tag) = 2
ORDER BY m.created_at DESC
LIMIT 0 , 20;

You should develop the habit of using JOIN syntax consistently. Mixing JOIN and comma-style joins can cause some subtle problems.

Here's an alternative query, that pulls some of the joins into a non-correlated subquery, so you avoid a Cartesian product between t and x, and eliminate the DISTINCT modifiers in the group functions.

SELECT m.*, u.*, GROUP_CONCAT(x.tag) AS tags
FROM message m
 JOIN `user` u ON (u.id = m.user_id)
 JOIN tag_message_rel r ON (m.id = r.message_id)
 JOIN tag x ON (x.id = r.tag_id)
WHERE m.id = ANY (
    SELECT m2.id 
    FROM message m2 
     JOIN tag_message_rel r2 ON (m2.id = r2.message_id)
     JOIN tag t ON (t.id = r2.tag_id)
    WHERE t.tag IN ('kikikiki', 'dsa') 
    GROUP BY m2.id 
    HAVING COUNT(t.tag) = 2)
GROUP BY m.id
ORDER BY m.created_at DESC
LIMIT 0 , 20;
梦里南柯 2024-07-22 17:38:11

您只能获得这两个标签,因为:

  1. t.tag IN ('kikikiki', 'dsa')。
    2 t.id IN (id-for-kikikiki, id-for-dsa)
  2. t.id = r.tag_id
  3. r.tag_id = x.id
  4. 组合 3 & 4、t.id = x.id
  5. 结合一切,x.tag IN ('kikikiki', 'dsa')

我想你想要的是加入第二个tag_message_rel。 将 t 连接到第一个; 将 x 连接到第二个; 将他们俩加入消息。 不完全确定这就是你想要的,因为你实际上并没有说......

You only get those two tags, because:

  1. t.tag IN ('kikikiki', 'dsa').
    2 t.id IN (id-for-kikikiki, id-for-dsa)
  2. t.id = r.tag_id
  3. r.tag_id = x.id
  4. Combining 3 & 4, t.id = x.id
  5. Combining everything, x.tag IN ('kikikiki', 'dsa')

I think what you want is to join a second tag_message_rel. Join t to the first one; join x to the second one; join them both to message. Not completely sure this is what you want, as you didn't actually say...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文