强制mySQL加入表(执行我需要的未优化查询)
这有点奇怪。我有下一个问题:强制mySQL加入表(执行我需要的未优化查询),mysql,sql-match-all,Mysql,Sql Match All,这有点奇怪。我有下一个问题: 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
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
我会得到我想要的消息,但是标签会将标签表中的所有标签用逗号分隔。如果我把线留在那里,我只会得到那两个标签。
如果我使用explain,我会得到:
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
现在我不是这方面的专家,但我认为问题在于它在优化查询的过程中拒绝重新连接表
你觉得怎么样?有什么快速解决方法吗?您只会得到这两个标签,因为:
我想你想要的是加入第二个
标记消息\u rel
。将t
连接到第一个;将x
连接到第二个;将它们连接到消息
。不完全确定这是您想要的,因为您实际上没有说…您只得到这两个标签,因为:
我想你想要的是加入第二个
标记消息\u rel
。将t
连接到第一个;将x
连接到第二个;将它们连接到消息
。不完全确定这是您想要的,因为您实际上没有说…问题是您试图连接到标记表两次,但您确实需要连接到标记消息\u rel
表两次,并从每一次连接到标记表中的相应行
可以将“表别名”看作是指表中的一行,而不是表本身。这个想法帮助我更好地理解复杂连接
下面是我如何编写该查询的:
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
语法的习惯。混合使用连接
和逗号样式的连接可能会导致一些微妙的问题
这里有一个替代查询,它将一些联接拉入一个不相关的子查询中,这样就避免了t
和x
之间的笛卡尔乘积,并消除了组函数中的不同的
修饰符
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;
问题是,您试图两次加入标记
表,但确实需要两次加入tag\u message\u rel
表,并从每一次加入到标记
表中的相应行
可以将“表别名”看作是指表中的一行,而不是表本身。这个想法帮助我更好地理解复杂连接
下面是我如何编写该查询的:
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
语法的习惯。混合使用连接
和逗号样式的连接可能会导致一些微妙的问题
这里有一个替代查询,它将一些联接拉入一个不相关的子查询中,这样就避免了t
和x
之间的笛卡尔乘积,并消除了组函数中的不同的
修饰符
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;