子查询的替代方案
给出下表:
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 | +----------+-----------------+
但是,当查询大量数据时,它会变得有点慢。
我的问题是是否有一种方法可以在不使用子查询的情况下返回此结果,以及这种替代方法是否更快。
提前致谢。
Given the following tables:
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');
My need is for a query to select all titles that are not connected to a given subject in the rank table.
I have this working via a subquery:
SELECT title_id, title FROM title
WHERE title_id NOT IN (SELECT title_id FROM rank WHERE subject_id=2)
This returns the desired list:
+----------+-----------------+ | title_id | title | +----------+-----------------+ | 3 | and yet another | | 4 | one more | | 5 | adding more | | 6 | yes, another | | 7 | well, let's see | +----------+-----------------+
However, it gets a little slow when a large set of data is queried.
My question is if there is a way to return this result without the use of a subquery and if this alternative is any speedier.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
MySQL 的连接速度通常更快,但更快的子查询正在开发中。
像往常一样,您需要在外键 (rank.title_id) 上以及可能在查询键 (rank.subject_id) 上设置索引。
如果您想了解更多详细信息,您应该阅读有关
[LEFT JOIN][1]
的 MySQL 文档。ON
还有一个很好的技巧,使其与WHERE
不同。MySQL is usually faster with joins, though faster sub-queries are work in progress.
As usual, you'll need to set up indexes on the foreign key (rank.title_id) and probably on the queried key (rank.subject_id).
You should read the MySQL documentation on
[LEFT JOIN][1]
if you want more details. There's also a nice trick withON
that makes it different fromWHERE
.MySQL EXPLAIN 命令会告诉您查询在哪里需要帮助。例如
EXPLAIN select title_id, title FROM title WHERE title_id NOT IN (select title_id fromrank where subject_id=2)
我的猜测是,真正的问题是你没有对rank.subject_id建立索引,并且这会导致表扫描(当排名有很多行时)。
The MySQL EXPLAIN command will tell you where your query needs help. e.g.
EXPLAIN select title_id, title FROM title WHERE title_id NOT IN (select title_id from rank where subject_id=2)
My guess is that the true problem is that you don't have an index on rank.subject_id and that's causing a table scan (when rank has lots of rows).
请在 subject_id 和 title_id 上创建两个索引并尝试相同的操作。
Please create two indexes on subject_id and title_id and try the same.