子查询的替代方案

发布于 2024-12-11 06:45:31 字数 1973 浏览 0 评论 0原文

给出下表:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

懒猫 2024-12-18 06:45:31

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 不同。

MySQL is usually faster with joins, though faster sub-queries are work in progress.

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

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 with ONthat makes it different from WHERE.

南城旧梦 2024-12-18 06:45:31

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).

野味少女 2024-12-18 06:45:31

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

Please create two indexes on subject_id and title_id and try the same.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文