子查询的替代方案

时间:2011-10-21 02:50:12

标签: mysql sql subquery

鉴于以下表格:

CREATE TABLE IF NOT EXISTS `rank` ( 
`rank_id` bigint(20) NOT NULL AUTO_INCREMENT, 
`rank` int(10) NOT NULL DEFAULT '0', 
`subject_id` int(10) NOT NULL DEFAULT '0', 
`title_id` int(10) NOT NULL DEFAULT '0', 
`source_id` int(10) NOT NULL DEFAULT '0'
PRIMARY KEY (`rank_id`) 
) ENGINE=MyISAM; 

INSERT INTO `rank` (`rank_id`, `rank`, `subject_id`, `title_id`, `source_id`) VALUES 
(23, 0, 2, 1, 1), 
(22, 0, 1, 1, 1), 
(15, 0, 2, 2, 2), 
(14, 0, 2, 2, 1), 
(20, 0, 1, 3, 2), 
(18, 0, 1, 4, 2), 
(19, 0, 1, 5, 2), 
(21, 0, 1, 3, 1), 
(24, 0, 1, 6, 2); 

CREATE TABLE IF NOT EXISTS `title` ( 
`title_id` bigint(20) NOT NULL AUTO_INCREMENT, 
`title` varchar(255) DEFAULT NULL, 
`description` text, 
`pre` varchar(255) DEFAULT NULL, 
`last_modified_by` varchar(50) DEFAULT NULL, 
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
PRIMARY KEY (`title_id`) 
) ENGINE=MyISAM; 

INSERT INTO `title` (`title_id`, `title`, `last_modified`) VALUES 
(1, 'new item', ' ', '2011-10-20 19:10:48'), 
(2, 'another test', '2011-10-20 19:10:48'), 
(3, 'and yet another', '2011-10-20 19:10:48'), 
(4, 'one more', ' ', '2011-10-20 19:10:48'), 
(5, 'adding more', ' ', '2011-10-20 19:10:48'), 
(6, 'yes, another', ' ', '2011-10-20 19:10:48'), 
(7, 'well, let''s see', ' ', '2011-10-20 19:10:48'); 

我需要一个查询来选择排名表中未连接到给定主题的所有标题。

我通过子查询工作:

SELECT title_id, title FROM title
WHERE title_id NOT IN (SELECT title_id FROM rank WHERE subject_id=2)

返回所需的列表:

+----------+-----------------+ 
| title_id | title           | 
+----------+-----------------+ 
| 3        | and yet another | 
| 4        | one more        | 
| 5        | adding more     | 
| 6        | yes, another    | 
| 7        | well, let's see | 
+----------+-----------------+ 

但是,当查询大量数据时,它会变得有点慢。

我的问题是,如果有一种方法可以在不使用子查询的情况下返回此结果,并且如果这种替代方法更快。

提前致谢。

3 个答案:

答案 0 :(得分:3)

对于连接,MySQL通常更快,但更快的子查询正在进行中。

SELECT t.*
FROM title AS t
LEFT JOIN rank AS r ON (t.title_id = r.title_id AND r.subject_id = 2)
WHERE r.title_id IS NULL

像往常一样,您需要在外键(rank.title_id)上设置索引,并且可能需要在查询键(rank.subject_id)上设置索引。

如果您需要更多详细信息,请阅读[LEFT JOIN][1]上的MySQL文档。 ON还有一个很好的技巧,它与WHERE不同。

答案 1 :(得分:1)

MySQL EXPLAIN命令将告诉您查询需要帮助的位置。例如EXPLAIN select title_id, title FROM title WHERE title_id NOT IN (select title_id from rank where subject_id=2)

我的猜测是,真正的问题是你没有对rank.subject_id的索引,而是导致表扫描(当排名有很多行时)。

答案 2 :(得分:1)

请在subject_id和title_id上​​创建两个索引并尝试相同。