我有以下表格:users
, tags
, tags_data
.
tags_data
包含tag_id
和user_id
列以将1 个用户与多个标签的关系链接users
起来。tags
tag_id
列出具有1001和1003或 tag_id
1004的所有用户的最佳方式是什么?
编辑:我的意思是,也可能有其他相关的标签,只要肯定有 1004 OR (1001 AND 1003)。
目前我有两种方法可以做到这一点,都UNION
在派生表中使用 a ,无论是在FROM
子句中还是在INNER JOIN
子句中......
SELECT subsel.user_id, users.name
FROM ( SELECT user_id
FROM tags_data
WHERE tag_id IN (1001, 1003)
GROUP BY user_id
HAVING COUNT(tag_id)=2
UNION
SELECT user_id
FROM tags_data
WHERE tag_id=1004
) AS subsel
LEFT JOIN users ON subsel.user_id=users.user_id
或者
SELECT users.user_id, users.name
FROM users
INNER JOIN ( SELECT user_id
FROM tags_data
WHERE tag_id IN (1001, 1003)
GROUP BY user_id
HAVING COUNT(tag_id)=2
UNION
SELECT user_id
FROM tags_data
WHERE tag_id=1004
) AS subsel ON users.user_id=subsel.user_id
还有其他表,我将对此进行LEFT JOIN
讨论。表中有 50k+ 行,users
表中有 150k+ 行tags_data
。
这是将数据导出到另一个系统的批处理作业,因此不是最终用户运行的实时查询,因此性能并不是非常关键。但是,我想尝试并获得最好的结果。派生表的查询实际上应该非常快,并且在我向返回给客户端的结果添加进一步的连接、函数和计算字段之前缩小结果集的范围是有意义的。稍后我将在更大的数据集上运行这些,以查看是否存在任何性能差异,但运行EXPLAIN
显示几乎相同的执行计划。
一般来说,UNIONs
除非绝对必要,否则我会尽量避免。但我认为在这种情况下,我几乎必须有一个UNION
定义的地方,因为这两个实际上不相关的标准。
我可以在这里使用另一种方法吗?
对于这类问题,是否有某种特定的数据库术语?
完整示例架构:
CREATE TABLE IF NOT EXISTS `tags` (
`tag_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`tag_name` varchar(255) NOT NULL,
PRIMARY KEY (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1006 ;
INSERT INTO `tags` (`tag_id`, `tag_name`) VALUES
(1001, 'tag1001'),
(1002, 'tag1002'),
(1003, 'tag1003'),
(1004, 'tag1004'),
(1005, 'tag1005');
CREATE TABLE IF NOT EXISTS `tags_data` (
`tags_data_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
PRIMARY KEY (`tags_data_id`),
KEY `user_id` (`user_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ;
INSERT INTO `tags_data` (`tags_data_id`, `user_id`, `tag_id`) VALUES
(1, 1, 1001),
(2, 1, 1002),
(3, 1, 1003),
(4, 5, 1001),
(5, 5, 1003),
(6, 5, 1005),
(7, 8, 1004),
(8, 9, 1001),
(9, 9, 1002),
(10, 9, 1004);
CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ;
INSERT INTO `users` (`user_id`, `name`) VALUES
(1, 'user1'),
(2, 'user2'),
(3, 'user3'),
(4, 'user4'),
(5, 'user5'),
(6, 'user6'),
(7, 'user7'),
(8, 'user8'),
(9, 'user9'),
(10, 'user10');