Fra*_*kie 6 mysql sql tags join left-join
我正试图找到最有效的方法来解决这个问题,但我必须告诉你,我已经把它弄得一团糟.环顾四周,没有发现任何相关性,所以在这里.
如何选择与所需项目具有相似标签的所有项目?
以此表为例:(
sql代码重新创建表格)
project 1 -> tagA | tagB | tagC
project 2 -> tagA | tagB
project 3 -> tagA
project 4 -> tagC
Run Code Online (Sandbox Code Playgroud)
选择项目1应返回所有项目.
选择项目4应仅返回项目项目1
到目前为止,我的查询非常依赖于左连接,并且肯定有更好的方法来执行此操作:
SELECT all_tags.project_id, all_tags.tag_id, final.title, tag.tag
FROM projects AS p
LEFT JOIN projects_to_tags AS pt ON p.num = pt.project_id
LEFT JOIN projects_to_tags AS all_tags ON pt.tag_id = all_tags.tag_id
LEFT JOIN projects AS final ON all_tags.project_id = final.num
LEFT JOIN tags AS tag ON all_tags.tag_id = tag.tag_id
WHERE p.num = 4
GROUP BY final.num
Run Code Online (Sandbox Code Playgroud)
谢谢大家的意见.我虽然与大家分享一下100k项目数据库的所有查询的平均结果,100k标签数据库与100k projects_to_tags关系.所有查询都已更改为要求project_1.
甜蜜和短暂:
0.0160 sec - OMG Ponies - Using JOINS
0.0208 sec - jdelard
0.2581 sec - OMG Ponies - Using EXISTS
0.2777 sec - OMG Ponies - Using IN
0.5295 sec - Emtucifor - updated query
0.5088 sec - Emtucifor - first query
Run Code Online (Sandbox Code Playgroud)
非常感谢大家.将相应地更新我的所有查询.
这里包括所有查询和各自的MySQL EXPLAIN以及时间
===============================================================================================================================================
Emtucifor - updated query
===============================================================================================================================================
Showing rows 0 - 1 (2 total, Query took 0.5295 sec)
SELECT *
FROM projects AS L
WHERE L.num !=1-- instead of <> PT2.project_id inside
AND EXISTS (
SELECT 1
FROM projects_to_tags PT
INNER JOIN projects_to_tags PT2 ON PT.tag_id = PT2.tag_id
WHERE L.num = PT.project_id
AND PT2.project_id =1
)
LIMIT 0 , 30
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY L ALL PRIMARY NULL NULL NULL 100000 Using where
2 DEPENDENT SUBQUERY PT2 ref project_id project_id 4 const 1 Using index
2 DEPENDENT SUBQUERY PT ref project_id project_id 8 test.L.num,test.PT2.tag_id 12000 Using index
===============================================================================================================================================
Emtucifor - first query
===============================================================================================================================================
Showing rows 0 - 1 (2 total, Query took 0.5088 sec)
SELECT *
FROM projects AS L
WHERE
EXISTS (
SELECT 1
FROM projects_to_tags PT
INNER JOIN projects_to_tags PT2 ON PT.tag_id = PT2.tag_id
WHERE L.num = PT.project_id
AND PT2.project_id =1
AND PT2.project_id <> L.num
)
LIMIT 0 , 30
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY L ALL NULL NULL NULL NULL 100000 Using where
2 DEPENDENT SUBQUERY PT2 ref project_id project_id 4 const 1 Using index
2 DEPENDENT SUBQUERY PT ref project_id project_id 8 test.L.num,test.PT2.tag_id 12000 Using where; Using index
===============================================================================================================================================
jdelard
===============================================================================================================================================
Showing rows 0 - 1 (2 total, Query took 0.0208 sec)
SELECT p.num, p.title
FROM projects_to_tags pt1, projects_to_tags pt2, projects p
WHERE pt1.project_id =1
AND pt2.project_id !=1
AND pt1.tag_id = pt2.tag_id
AND p.num = pt2.project_id
GROUP BY pt2.project_id
LIMIT 0 , 30
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE pt1 ref project_id project_id 4 const 1 Using index; Using temporary; Using filesort
1 SIMPLE pt2 index project_id project_id 8 NULL 75001 Using where; Using index
1 SIMPLE p eq_ref PRIMARY PRIMARY 4 test.pt2.project_id 1
===============================================================================================================================================
OMG Ponies - Using IN
===============================================================================================================================================
Showing rows 0 - 2 (3 total, Query took 0.2777 sec)
SELECT p . *
FROM projects p
JOIN projects_to_tags pt ON pt.project_id = p.num
WHERE pt.tag_id
IN (
SELECT x.tag_id
FROM projects_to_tags x
WHERE x.project_id =1
)
LIMIT 0 , 30
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY pt index project_id project_id 8 NULL 100001 Using where; Using index
1 PRIMARY p eq_ref PRIMARY PRIMARY 4 test.pt.project_id 1
2 DEPENDENT SUBQUERY x ref project_id project_id 8 const,func 12000 Using where; Using index
===============================================================================================================================================
OMG Ponies - Using EXISTS
===============================================================================================================================================
Showing rows 0 - 2 (3 total, Query took 0.2581 sec)
SELECT p . *
FROM projects p
JOIN projects_to_tags pt ON pt.project_id = p.num
WHERE EXISTS (
SELECT NULL
FROM projects_to_tags x
WHERE x.project_id = 1
AND x.tag_id = pt.tag_id
)
LIMIT 0 , 30
===============================================================================================================================================
OMG Ponies - Using JOINS
===============================================================================================================================================
Showing rows 0 - 2 (3 total, Query took 0.0160 sec)
SELECT DISTINCT p . *
FROM projects p
JOIN projects_to_tags pt ON pt.project_id = p.num
JOIN projects_to_tags x ON x.tag_id = pt.tag_id
AND x.project_id = 1
LIMIT 0 , 30
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE x ref project_id project_id 4 const 1 Using index; Using temporary
1 SIMPLE pt index project_id project_id 8 NULL 75001 Using where; Using index
1 SIMPLE p eq_ref PRIMARY PRIMARY 4 test.pt.project_id 1
Run Code Online (Sandbox Code Playgroud)
SQL代码复制/粘贴和乱七八糟.
CREATE TABLE IF NOT EXISTS `projects` (
`num` int(2) NOT NULL auto_increment,
`title` varchar(30) NOT NULL,
PRIMARY KEY (`num`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
INSERT INTO `projects` (`num`, `title`) VALUES(1, 'project 1'),(2, 'project 2'),(3, 'project 3'),(4, 'project 4');
CREATE TABLE IF NOT EXISTS `projects_to_tags` (
`project_id` int(2) NOT NULL,
`tag_id` int(2) NOT NULL,
KEY `project_id` (`project_id`,`tag_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `projects_to_tags` (`project_id`, `tag_id`) VALUES(1, 1),(1, 2),(1, 3),(2, 1),(2, 2),(3, 1),(4, 3);
CREATE TABLE IF NOT EXISTS `tags` (
`tag_id` int(2) NOT NULL auto_increment,
`tag` varchar(30) NOT NULL,
PRIMARY KEY (`tag_id`),
UNIQUE KEY `tag` (`tag`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
INSERT INTO `tags` (`tag_id`, `tag`) VALUES(1, 'tag a'),(2, 'tag b'),(3, 'tag c');
Run Code Online (Sandbox Code Playgroud)
在下列任何一种情况下,如果您不知道PROJECT.num/ PROJECT_TO_TAGS.project_id,则必须加入PROJECTS表中以获取id值,以找出它与之关联的标记.
SELECT p.*
FROM PROJECTS p
JOIN PROJECTS_TO_TAGS pt ON pt.project_id = p.num
WHERE pt.tag_id IN (SELECT x.tag_id
FROM PROJECTS_TO_TAGS x
WHERE x.project_id = 4)
Run Code Online (Sandbox Code Playgroud)
SELECT p.*
FROM PROJECTS p
JOIN PROJECTS_TO_TAGS pt ON pt.project_id = p.num
WHERE EXISTS (SELECT NULL
FROM PROJECTS_TO_TAGS x
WHERE x.project_id = 4
AND x.tag_id = pt.tag_id)
Run Code Online (Sandbox Code Playgroud)
这DISTINCT是必要的,因为JOIN会冒结果集中出现重复数据的风险......
SELECT DISTINCT p.*
FROM PROJECTS p
JOIN PROJECTS_TO_TAGS pt ON pt.project_id = p.num
JOIN PROJECTS_TO_TAGS x ON x.tag_id = pt.tag_id
AND x.project_id = 4
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1586 次 |
| 最近记录: |